2019-8-10 Async await를 이용한 비동기 해결

  • api서버를 통해 gmail api에 호출을 했다. getList의 경우 email의 id들을 가지고 오고, 가지고 온 id를 기반으로 getMessage나 getReceipt메소드를 통해 email의 내용을 가지고 온다.
    function infos(auth) {
    console.log('apiService infos called');
    getList(auth)
      .then((messages) => {
        return new Promise((resolve, reject) => {
          let infos = [];
          for (let i = 0; i < messages.length; i++) {
            getReceipt(auth, messages[i].id).then(msg => { infos.push(msg)}); }
          console.log('infos : ', infos);
          err ? reject(err) : resolve(infos);
        });
      });
    }
    
  • getList에 있는 messages의 id값을 순회하면서 getReceipt를 통해 json형태의 응답값들을 list에 담고 싶었다. 하지만 이슈가 있었다.
  • 당연히 위와 같은 코드로 생각을 했다. getList가 Promise를 리턴해주니 then으로 message를 받고. for문을 순회해서 선언한 infos에 push하는 형태를 바랬다.
  • 하지만 안됬다. 비동기안에서 비동기를 처리를 하다보니. 안됬다. async await을 이용해서 해결을 했다.
function getList(auth) {
  const gmail = google.gmail({version: 'v1', auth});
  return new Promise((resolve, reject) => {
    gmail.users.messages.list({userId: TEST_USERID, q: `from:Apple subject:영수증 -(구독 만료) -(구독 확인) "갱신 예정"`}, (err, res) => {
      err ? reject(err) : resolve(res.data.messages);
    });
  });
}

function getMessage(auth, id) {
  // id = 16c3b300da121d9c
  const gmail = google.gmail({version: 'v1', auth});
  return new Promise((resolve, reject) => {
    gmail.users.messages.get({auth: auth, userId: TEST_USERID, id: id,}, (err, res) => {
      err ? reject(err) : resolve(base64ToUtf8(res.data.payload.parts[1].body.data));
    });
  });
}

function getReceipt(auth, id) {
  // id = 16c3b300da121d9c
  const gmail = google.gmail({version: 'v1', auth});
  return new Promise((resolve, reject) => {
    gmail.users.messages.get({auth: auth, userId: TEST_USERID, id: id,}, (err, res) => {
      err ? reject(err) : resolve(getInfo(base64ToUtf8(res.data.payload.parts[1].body.data)));
    });
  });
}

async function infos(auth) {
  const messages = await getList(auth);
  return await Promise.all(messages.map(message => getReceipt(auth, message.id)))
}
  • async, await은 Promise이다. 따라서 Promise앞에 await을 붙일 수 있다.
  • infos라는 함수 앞에 async키워드를 붙여서 비동기함수로 선언한다.
  • await getList(auth)를 통해 messages에 getList의 결과가 응답할때까지 기다린다.
  • messages.map(message => getReceipt(auth, message.id))를 하면 messages의 내부배열을 순회하면서 getReceipt를 통해 얻은 결과값들을 list에 담는다. 각 리스트의 요소들은 promise형태로 저장이 된다.
  • Promise.all([promise, promise …]) Promise.all은 리스트를 인자로 받고, 주어진 모든 Promise중에 하나라도 reject가 되면 응답되지 않는다.
  • await Promise.all(messages.map(message => getReceipt(auth, message.id)))를 하면 json의 리스트로 결과를 받을 수 있다.

느낀점

  • 비동기에 대해서 잘몰랐고, 그나마 Promise가 익숙했는데, Promise안에서 Promise를 처리하려다 보니 이슈가 생겼었다. async await을 통해 간단하게 해결했고, 문법은 들어만 보다가 문제가 생겼을때 적용을 하니 이해가 쉬웠다.
Written on August 10, 2019