인프런 커뮤니티 질문&답변

iksukis8604님의 프로필 이미지

작성한 질문수

타입스크립트 입문 - 기초부터 실전까지

주요 메서드(조회) 타입 정의 및 실습 마무리

생성자에서 비동기처리

작성

·

934

1

  • - 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요!
  • - 먼저 유사한 질문이 있었는지 검색해보세요.
  • - 서로 예의를 지키며 존중하는 문화를 만들어가요.
  • - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.

안녕하세요 캡틴판교님, 강의 잘 듣고있습니다.

실습에서 구현한 클래스를 보면 생성자에서 비동기처리를 수행하는 함수가 실행되고(fetchData())있는데요, 

다음과같이 만들고 메소드를 실행했을 때 비동기처리때문인지 결과 값이 빈 배열이 나오는 것을 볼 수 있었습니다...

 

그래서 질문은

  1. 해당 실습코드처럼 클래스의 생성자에서 비동기처리를 하는 함수를 실행하는 방식을 많이 이용하나요? 뭔가 제 생각으로는 생성자에서 비동기로 데이터를 받아와 멤버변수에 값을 넣는 경우 멤버함수(메소드)를 외부에서 이용할 경우 위처럼 문제가 생길 것 같아서요.
  2. 실습에서 구현한 클래스를 어떻게 잘 사용할 수 있을까요? 제가 이해한 실습코드의 클래스 로직은 이렇습니다. 
    1. 클래스가 만들어지고(new AddressBook()) 클래스 생성자에서 fetchData() - fetchContracts()실행 -> 비동기로 처리됨
    2. 1이 처리되어 멤버변수 contracts에 받아온 데이터가 할당되기 전 외부의 코드 실행됨(위 스샷)
    3. 1이 처리되기 전에 실행되었기 때문에 빈배열 출력

--클래스의 메소드를 사용하고 싶은 경우 생성자가 실행된 이후 메소드들을 실행할 수 있도록 async-await나 프로미스를 이용해 처리를 해줘야 할 것으로 생각되는데, 어떻게 구현할 수 있을지 감이 오지 않습니다... 도와주실 수 있으실까요?

 

 

 

답변 3

1

답변 감사합니다! 

0

interface PhoneNumberDictionary {
  [phone: string]: { num: number };
}

interface Contact {
  name: string;
  address: string;
  phones: PhoneNumberDictionary;
}

enum PhoneType {
  Home = 'home',
  Office = 'office',
  Studio = 'studio',
}

// api
function fetchContacts(): Promise<Array<Contact>> {
  const contacts: Array<Contact> = [
    {
      name: 'Tony',
      address: 'Malibu',
      phones: {
        home: { num: 11122223333 },
        office: { num: 44455556666 },
      },
    },
    {
      name: 'Banner',
      address: 'New York',
      phones: {
        home: { num: 77788889999 },
      },
    },
    {
      name: '마동석',
      address: '서울시 강남구',
      phones: {
        home: { num: 213423452 },
        studio: { num: 314882045 },
      },
    },
  ];
  return new Promise(resolve => {
    setTimeout(() => resolve(contacts), 2000);
  });
}

// main
class AddressBook {
  contacts: Array<Contact>;

  constructor() {
    this.contacts = [];
    // this.fetchData();
  }

  async fetchData(): Promise<void> {
    // fetchContacts().then(res => {
    //   this.contacts = res;
    // });
    const res = await fetchContacts();
    this.contacts = res;
  }

  findContactByName(name: string): Array<Contact> {
    return this.contacts.filter(contact => contact.name === name);
  }

  findContactByAddress(address: string): Array<Contact> {
    return this.contacts.filter(contact => contact.address === address);
  }

  findContactByPhone(
    phoneNumber: number,
    phoneType: PhoneType
  ): Array<Contact> {
    return this.contacts.filter(
      contact => contact.phones[phoneType].num === phoneNumber
    );
  }

  addContact(contact: Contact): void {
    this.contacts.push(contact);
  }

  displayListByName(): Array<string> {
    return this.contacts.map(contact => contact.name);
  }

  displayListByAddress(): Array<string> {
    return this.contacts.map(contact => contact.address);
  }
}

(async (): Promise<AddressBook> => {
  console.log('Wait for 2 seconds..');

  const addressBook = new AddressBook();
  await addressBook.fetchData();
  return addressBook;
})().then(addressBook => {
  console.log(addressBook);
  console.log(addressBook.findContactByName('마동석'));
  console.log(addressBook.findContactByAddress('Malibu'));
  console.log(addressBook.findContactByPhone(77788889999, PhoneType.Home));
  console.log(addressBook.displayListByName());
  console.log(addressBook.displayListByAddress());
  console.log('=================================================');
  addressBook.addContact({
    name: 'Haguri',
    address: 'Jeonbuk',
    phones: {
      home: { num: 1011119999 },
      office: { num: 6312345678 },
    },
  });
  console.log(addressBook.contacts);
});

위 코드는 제가 작성하고 테스트 해본 코드이구요. 참조 링크는 아래와 같습니다.

https://stackoverflow.com/questions/36363278/can-async-await-be-used-in-constructors

0

안녕하세요 좋은 질문이네요. 보통 클래스 생성을 비동기로 처리하지는 않기 때문에 클래스를 생성하고 나서 비동기 처리가 필요한 로직은 async, 프로미스 등을 붙여 명시적으로 비동기 처리를 해줍니다. 질문하신 내용들은 클래스 설계를 어떻게 하느냐에 따라서 답이 달라질 것 같아요. 보통 클래스를 모델 레이어로 설계하거나 MVC 모델의 Controller로 설계하거나 목적에 따라 다르게 설계합니다.

마찬가지로 제가 설계한 클래스는 학습 목적으로 설계된 구조이지 실제 애플리케이션에서 저렇게 꼭 써야합니다 라고 설계한 건 아닙니다. 더불어서 제가 만약 저 클래스를 실제 DOM 조작과 연계한 코드로 활용한다고 한다면 클래스를 생성하고 바로 어떤 메서드를 호출하는 것이 아니라 화면에 렌더링 될 때 이미 데이터를 다 들고와 있도록 클래스를 생성해 두었을 것 같아요.

질문하신 내용이 단편적으로 답변하기가 어려워서 답변이 길어졌네요. 보시고 또 궁금하신거 있으면 알려주세요 :)