TIL 39. asyncとwait

23823 ワード

より簡便な方法で「基本情報」を扱う対象は、asyncおよびawaitである.asyncawait方法やコールバックを必要とせずに非同期実行コードを記述することができ、同期実行コードのように、より簡単かつ容易にコードを記述することができる.
fetch("https://jsonplaceholder.typicode.com/users")
  .then((response) => response.text())
  .then((result) => {
    console.log(result);
  });

async function fetchAndPrint() {
  // 함수 앞에 붙은 async는 이 함수 안에 비동기적으로 실행이 필요한 코드가 있다는 것을 암시
  const response = await fetch("https://jsonplaceholder.typicode.com/users");
  const result = await response.text();
  // await은 뒤에 붙은 코드가 실행되고 fulfilled 혹은 rejected 상태의 프로미스 객체를 
  // 리턴할 때까지 기다렸다가 작업이 완료된 객체를 리턴한다.
  // await은 async 함수 내부에서만 사용할 수 있다.
  console.log(result);
}

fetchAndPrint();

async関数の実行順序


async awaitはコードが見える順序で実行されないことを覚えておいてください.
async function fetchAndPrint() {
  console.log(2); // 3. 2가 출력되고
  const response = await fetch("https://jsonplaceholder.typicode.com/users"); //4. fetch 함수가 실행되면 실행 순서는 함수 바깥으로 이동한다.
  console.log(7); // 6. fetch 함수가 fulfilled 상태가 되어 해당 값이 response에 할당되면 이후 7이 출력된다.
  const result = await response.text(); // 7. 두번째 fetch 함수가 실행되면 실행 순서는 다시 바깥으로 나가서
  console.log(result); // 9. 두번째 await 작업이 완료되면 result 가 출력된다.
}

console.log(1); // 1. 1이 가장 먼저 출력되고
fetchAndPrint(); // 2. async 함수가 출력된다.
console.log(3); // 5. 나머지 코드들을 다 실행시킨다. 그 이후로는 await 뒤 fetch 함수의 프로미스 객체가 fullfilled 상태가 되기를 기다렸다가
console.log(4);
console.log(5);
console.log(6);
// 8. 밖에는 더이상 실행을 기다리는 코드가 없고 다시 await 뒤 함수의 프로미스 객체가 fulfilled 상태가 되기를 기다렸다가

// 결과 : 1,2,3,4,5,6,7,result

asyncエラーハンドル


async await文は、拒否された承諾オブジェクトをtry catch文に変換できます.
async function fetchAndPrint() {
  try {
    const response = await fetch(
      "https://jsonplaceholder.typicode.commmm/users"
    ); // 존재하지 않는 url로 rejected상태의 프로미스 객체가 리턴
    const result = await response.text();
    console.log(result);
  } catch (err) {
    // try 구문안의 코드 중 프로미스 객체가 rejected 되는 순간 catch 문으로 코드흐름 이동하고 err 파라미터로 작업실패정보가 넘어온다
    console.log(err);
  } finally {
    // 작업 결과에 상관없이 항상 실행
    console.log("exit");
  }
}

fetchAndPrint();


// 중요! async 함수는 항상 promise 객체를 리턴한다.
async function fetchAndPrint() {
  return 3;
}

fetchAndPrint(); // 3을 작업 성공 결과로 가진 fulfilled 상태의 프로미스 객체 리턴

async function fetchAndPrint() {
  return fetch("https://jsonplaceholder.typicode.com/users").then((response) =>
    response.text()
  );
}

fetchAndPrint(); // then 메소드가 리턴하는 프로미스 객체와 동일한 작업 성공 결과와 상태를 가진 프로미스 객체 리턴

async関数の戻り値


Promiseオブジェクトを返します.
async関数でpromiseオブジェクトが返されると、そのpromiseオブジェクトと同じ状態と操作結果を持つpromiseオブジェクトが返されます.
async function fetchAndPrint() {
  return Promise.resolve("Success"); // 프로미스 객체 리턴
}

fetchAndPrint(); // fulfilled 상태, 작업성공결과 Success 인 프로미스 객체 리턴
Promiseオブジェクト以外の値を返します.
完了した戻り値が操作に成功した結果のPromiseオブジェクトを返します.
async function fetchAndPrint() {
  return 3;
}

fetchAndPrint();
値は返されませんでした.
完了し、操作の成功結果として定義されていないPromiseオブジェクトが返されます.
async function fetchAndPrint() {
  console.log("Hello Programming!");
}

fetchAndPrint();
async関数内部にエラーが発生した場合
オブジェクトが拒否されている場合は、操作に失敗した情報を持つPromiseオブジェクトが返されます.
async function fetchAndPrint() {
  throw new Error("Fail");
}

fetchAndPrint();

asyncのasync関数


async関数はpromisオブジェクトを返すため、async関数では別のaync関数を自由に使用してwaitとともに使用することもできます.
const applyPrivacyRule = async function (users) {
  const resultWithRuleApplied = users.map((user) => {
    const keys = Object.keys(user);
    const userWithoutPrivateInfo = {};
    keys.forEach((key) => {
      if (key !== "address" && key !== "phone") {
        userWithoutPrivateInfo[key] = user[key];
      }
    });
    return userWithoutPrivateInfo;
  });

  const p = new Promise((resolve) => {
    setTimeout(() => {
      resolve(resultWithRuleApplied);
    }, 2000);
  });
  return p;
};

async function getUsers() {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/users");
    const result = await response.text();
    const users = JSON.parse(result);
    const resultWithPrivacyRuleApplied = await applyPrivacyRule(users);
    return resultWithPrivacyRuleApplied;
  } catch (err) {
    console.log(err);
  } finally {
    console.log("exit");
  }
}

getUsers().then((result) => {
  console.log(result);
});
これまでcallback,promisty,async awaitは相補的であった
コールバックを直接関数パラメータに渡す従来の非同期実行関数では、setInterval、addEventListenerのように、1回の呼び出しではなく複数回の呼び出しが必要な関数を使用することはできません.Promiseオブジェクトがステータスに達するか拒否されると、そのステータスと結果は変更されません.
async/await構文の場合、awaitはasync関数でのみ使用でき、コードの最上位レベル(関数ブロックに含まれるコードの最上位レベルではない)では使用できません.したがって、コードの最上位レベルでasync関数が返されるPromiseオブジェクトの操作に成功した結果を取得する場合はawaitは使用できませんが、thenメソッドを使用する必要があります.