>  기사  >  웹 프론트엔드  >  JavaScript에서 Promise 및 Async/Await를 빠르게 학습하세요.

JavaScript에서 Promise 및 Async/Await를 빠르게 학습하세요.

青灯夜游
青灯夜游앞으로
2021-01-30 10:01:051445검색

JavaScript에서 Promise 및 Async/Await를 빠르게 학습하세요.

일반적으로 개발 중에는 네트워크 API 작업을 쿼리하는 데 시간이 많이 걸리므로 응답을 기다리는 데 시간이 걸릴 수 있습니다. 따라서 요청 시 프로그램이 응답하지 않는 상황을 피하기 위해 비동기 프로그래밍은 개발자의 기본 기술이 되었습니다.

JavaScript에서 비동기 작업을 다룰 때 우리는 일반적으로 "Promise"라는 개념을 듣습니다. 그러나 작동 방식과 사용 방법을 이해하는 것은 추상적이고 이해하기 어려울 수 있습니다.

관련 권장사항: "javascript 비디오 튜토리얼"

그래서 이 글에서는 개념과 사용법을 더 빨리 이해할 수 있도록 실용적인 방법을 사용할 것이므로 많은 전통적인 건조 튜토리얼부터 시작하겠습니다. 다음 네 가지 예:

  • 예 1: 생일에 대한 Promise의 기본 설명
  • 예 2: 추측 게임
  • 예 3: 웹 API에서 국가 정보 가져오기
  • 예 4: 이웃 국가 목록 가져오기 of a country in Web API

예 1: birthday를 사용하여 Promise의 기본 설명

먼저 Promise의 기본 형태를 살펴보겠습니다.

프로미스는 실행될 때 보류(실행 중), 이행(성공), 거부(실패)의 세 가지 상태로 나뉩니다.

new Promise(function(resolve, reject) {
    if (/* 异步操作成功 */) {
        resolve(value); //将Promise的状态由padding改为fulfilled
    } else {
        reject(error); //将Promise的状态由padding改为rejected
    }
})
实现时有三个原型方法then、catch、finally
promise
.then((result) => {
    //promise被接收或拒绝继续执行的情况
})
.catch((error) => {
    //promise被拒绝的情况
})
.finally (() => {
    //promise完成时,无论如何都会执行的情况
})

기본 폼 소개가 완료되었으니, 다음 예시를 살펴보겠습니다.

사용자 스토리: 내 친구 Kayo가 2주 후에 생일 파티를 위해 케이크를 만들어 주기로 약속했습니다.

모든 일이 잘 되어 카요가 아프지 않으면 일정량의 케이크를 받을 수 있지만, 카요가 아프면 케이크가 없습니다. 하지만 케이크가 있든 없든 우리는 여전히 생일 파티를 할 것입니다.

이 예에서는 위의 배경 이야기를 JS 코드로 변환합니다. 먼저 Promise를 반환하는 함수를 만들어 보겠습니다.

const onMyBirthday = (isKayoSick) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (!isKayoSick) {
        resolve(2);
      } else {
        reject(new Error("I am sad"));
      }
    }, 2000);
  });
};

JavaScript에서는 new Promise()를 사용하여 (해결, 거부)=>{} 매개변수가 있는 함수를 허용하는 새 Promise를 생성할 수 있습니다.

이 함수에서는 Resolve와 Reject가 기본으로 제공되는 콜백 함수입니다. 위의 코드를 자세히 살펴보겠습니다.

2000ms 후에 onMyBirthday 함수를 실행했을 때.

  • Kayo가 아프지 않으면 2를 매개변수로 하여 해결 함수를 실행합니다.
  • Kayo가 아프면 new Error("I am sad")를 매개변수로 사용하여 Reject를 실행합니다. 거부하고 싶은 것은 무엇이든 매개변수로 전달할 수 있지만 Error 객체를 전달하는 것이 좋습니다.

이제 onMyBirthday()가 Promise를 반환하므로 then, catch 및 finally 메서드에 액세스할 수 있습니다. 또한 이전에 해결 및 거부하고 이를 사용하여 포착하기 위해 전달된 매개변수에 액세스할 수 있습니다.

다음 코드를 통해 개념을 이해해 봅시다

카요가 아프지 않다면

onMyBirthday(false)
  .then((result) => {
    console.log(`I have ${result} cakes`); // 控制台打印“I have 2 cakes” 
  })
  .catch((error) => {
    console.log(error); // 不执行
  })
  .finally(() => {
    console.log("Party"); // 控制台打印“Party”
  });

카요가 아프다면

onMyBirthday(true)
  .then((result) => {
    console.log(`I have ${result} cakes`); // 不执行 
  })
  .catch((error) => {
    console.log(error); // 控制台打印“我很难过”
  })
  .finally(() => {
    console.log("Party"); // 控制台打印“Party”
  });

이 예제를 통해 Promise의 기본 개념을 이해하실 수 있을 거라 믿습니다.

예제 2부터 시작하겠습니다

예제 2: 숫자 추측 게임

기본 요구 사항:

  • 사용자는 어떤 숫자든 입력할 수 있습니다.
  • 시스템은 1부터 6까지의 숫자를 무작위로 생성합니다
  • 사용자가 입력하면 a 숫자 시스템 난수와 같으면 2포인트를 부여합니다
  • 사용자가 입력한 숫자가 시스템 난수와 1만큼 다르면 1포인트를 부여하고, 그렇지 않으면 사용자는 0포인트가 주어집니다
  • 사용자는 원하는 만큼 플레이할 수 있습니다

위 요구 사항에 대해 먼저 enterNumber 함수를 만들고 Promise를 반환합니다.

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    // 从这开始编码
  });
};

가장 먼저 사용자에게 번호를 요청합니다. 1에서 6 사이의 숫자를 무작위로 선택합니다.

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    const userNumber = Number(window.prompt("Enter a number (1 - 6):")); // 向用户索要一个数字
    const randomNumber = Math.floor(Math.random() * 6 + 1); // 选择一个从1到6的随机数
  });
};

사용자가 숫자의 값이 아닌 숫자를 입력한 경우. 이 경우, 거부 함수를 호출하고 오류를 발생시킵니다:

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    const userNumber = Number(window.prompt("Enter a number (1 - 6):")); // 向用户索要一个数字
    const randomNumber = Math.floor(Math.random() * 6 + 1); //选择一个从1到6的随机数

    if (isNaN(userNumber)) {
      reject(new Error("Wrong Input Type")); // 当用户输入的值非数字,抛出异常并调用reject函数
    }
  });
};

다음으로 userNumber가 RanomNumber와 같은지 확인해야 하며, 같으면 사용자에게 2점을 주고 확인 함수를 실행하여 다음을 수행할 수 있습니다. 객체 { points: 2, randomNumber } 객체를 전달합니다.

userNumber와 RandomNumber의 차이가 1이면 사용자에게 1점을 줍니다. 그렇지 않으면 사용자에게 0점을 줍니다.

return new Promise((resolve, reject) => {
  const userNumber = Number(window.prompt("Enter a number (1 - 6):")); // 向用户索要一个数字
  const randomNumber = Math.floor(Math.random() * 6 + 1); // 选择一个从1到6的随机数

  if (isNaN(userNumber)) {
    reject(new Error("Wrong Input Type")); // 当用户输入的值非数字,抛出异常并调用reject函数
  }

  if (userNumber === randomNumber) {
    // 如果相等,我们给用户2分
    resolve({
      points: 2,
      randomNumber,
    });
  } else if (
    userNumber === randomNumber - 1 ||
    userNumber === randomNumber + 1
  ) {
    // 如果userNumber与randomNumber相差1,那么我们给用户1分
    resolve({
      points: 1,
      randomNumber,
    });
  } else {
    // 否则用户得0分
    resolve({
      points: 0,
      randomNumber,
    });
  }
});

다음으로 사용자에게 게임을 계속할지 묻는 또 다른 함수를 만들어 보겠습니다.

const continueGame = () => {
  return new Promise((resolve) => {
    if (window.confirm("Do you want to continue?")) { // 向用户询问是否要继续游戏
      resolve(true);
    } else {
      resolve(false);
    }
  });
};

게임을 강제로 종료하지 않기 위해 우리가 만든 Promise에서는 Reject 콜백을 사용하지 않습니다.

아래에서는 추측 논리를 처리하는 함수를 만듭니다.

const handleGuess = () => {
  enterNumber() // 返回一个Promise对象
    .then((result) => {
      alert(`Dice: ${result.randomNumber}: you got ${result.points} points`); // 当resolve运行时,我们得到用户得分和随机数 
      
      // 向用户询问是否要继续游戏
      continueGame().then((result) => {
        if (result) {
          handleGuess(); // If yes, 游戏继续
        } else {
          alert("Game ends"); // If no, 弹出游戏结束框
        }
      });
    })
    .catch((error) => alert(error));
};

handleGuess(); // 执行handleGuess 函数

在这当我们调用handleGuess函数时,enterNumber()返回一个Promise对象。

如果Promise状态为resolved,我们就调用then方法,向用户告知竞猜结果与得分,并向用户询问是否要继续游戏。

如果Promise状态为rejected,我们将显示一条用户输入错误的信息。

不过,这样的代码虽然能解决问题,但读起来还是有点困难。让我们后面将使用async/await 对hanldeGuess进行重构。

网上对于 async/await 的解释已经很多了,在这我想用一个简单概括的说法来解释:async/await就是可以把复杂难懂的异步代码变成类同步语法的语法糖

下面开始看重构后代码吧:

const handleGuess = async () => {
  try {
    const result = await enterNumber(); // 代替then方法,我们只需将await放在promise前,就可以直接获得结果

    alert(`Dice: ${result.randomNumber}: you got ${result.points} points`);

    const isContinuing = await continueGame();

    if (isContinuing) {
      handleGuess();
    } else {
      alert("Game ends");
    }
  } catch (error) { // catch 方法可以由try, catch函数来替代
    alert(error);
  }
};

通过在函数前使用async关键字,我们创建了一个异步函数,在函数内的使用方法较之前有如下不同:

  • 和then函数不同,我们只需将await关键字放在Promise前,就可以直接获得结果。
  • 我们可以使用try, catch语法来代替promise中的catch方法。

下面是我们重构后的完整代码,供参考:  

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    const userNumber = Number(window.prompt("Enter a number (1 - 6):")); // 向用户索要一个数字
    const randomNumber = Math.floor(Math.random() * 6 + 1); // 系统随机选取一个1-6的数字

    if (isNaN(userNumber)) {
      reject(new Error("Wrong Input Type")); // 如果用户输入非数字抛出错误
    }

    if (userNumber === randomNumber) { // 如果用户猜数字正确,给用户2分
      resolve({
        points: 2,
        randomNumber,
      });
    } else if (
      userNumber === randomNumber - 1 ||
      userNumber === randomNumber + 1
    ) { // 如果userNumber与randomNumber相差1,那么我们给用户1分
      resolve({
        points: 1,
        randomNumber,
      });
    } else { // 不正确,得0分
      resolve({
        points: 0,
        randomNumber,
      });
    }
  });
};

const continueGame = () => {
  return new Promise((resolve) => {
    if (window.confirm("Do you want to continue?")) { // 向用户询问是否要继续游戏
      resolve(true);
    } else {
      resolve(false);
    }
  });
};

const handleGuess = async () => {
  try {
    const result = await enterNumber(); // await替代了then函数

    alert(`Dice: ${result.randomNumber}: you got ${result.points} points`);

    const isContinuing = await continueGame();

    if (isContinuing) {
      handleGuess();
    } else {
      alert("Game ends");
    }
  } catch (error) { // catch 方法可以由try, catch函数来替代
    alert(error);
  }
};

handleGuess(); // 执行handleGuess 函数

我们已经完成了第二个示例,接下来让我们开始看看第三个示例。

示例3:从Web API中获取国家信息

一般当从API中获取数据时,开发人员会精彩使用Promises。如果在新窗口打开https://restcountries.eu/rest/v2/alpha/cn,你会看到JSON格式的国家数据。

通过使用Fetch API,我们可以很轻松的获得数据,以下是代码:

const fetchData = async () => {
  const res = await fetch("https://restcountries.eu/rest/v2/alpha/cn"); // fetch() returns a promise, so we need to wait for it

  const country = await res.json(); // res is now only an HTTP response, so we need to call res.json()

  console.log(country); // China's data will be logged to the dev console
};

fetchData();

现在我们获得了所需的国家/地区数据,让我们转到最后一项任务。

示例4:从Web API中获取一个国家的周边国家列表

下面的fetchCountry函数从示例3中的api获得国家信息,其中的参数alpha3Code 是代指该国家的国家代码,以下是代码

// Task 4: 获得中国周边的邻国信息
const fetchCountry = async (alpha3Code) => {
  try {
    const res = await fetch(
      `https://restcountries.eu/rest/v2/alpha/${alpha3Code}`
    );

    const data = await res.json();

    return data;
  } catch (error) {
    console.log(error);
  }
};

下面让我们创建一个fetchCountryAndNeighbors函数,通过传递cn作为alpha3code来获取中国的信息。

const fetchCountryAndNeighbors = async () => {
  const china= await fetchCountry("cn");

  console.log(china);
};

fetchCountryAndNeighbors();

在控制台中,我们看看对象内容:  

在对象中,有一个border属性,它是中国周边邻国的alpha3codes列表。

现在,如果我们尝试通过以下方式获取邻国信息。

const neighbors = 
    china.borders.map((border) => fetchCountry(border));

neighbors是一个Promise对象的数组。

当处理一个数组的Promise时,我们需要使用Promise.all。

const fetchCountryAndNeigbors = async () => {
  const china = await fetchCountry("cn");

  const neighbors = await Promise.all(
    china.borders.map((border) => fetchCountry(border))
  );

  console.log(neighbors);
};

fetchCountryAndNeigbors();

在控制台中,我们应该能够看到国家/地区对象列表。

以下是示例4的所有代码,供您参考:

const fetchCountry = async (alpha3Code) => {
  try {
    const res = await fetch(
      `https://restcountries.eu/rest/v2/alpha/${alpha3Code}`
    );
    const data = await res.json();
    return data;
  } catch (error) {
    console.log(error);
  }
};

const fetchCountryAndNeigbors = async () => {
  const china = await fetchCountry("cn");
  const neighbors = await Promise.all(
    china.borders.map((border) => fetchCountry(border))
  );
  console.log(neighbors);
};

fetchCountryAndNeigbors();

总结

完成这4个示例后,你可以看到Promise在处理异步操作或不是同时发生的事情时很有用。相信在不断的实践中,对它的理解会越深、越强,希望这篇文章能对大家理解Promise和Async/Await带来一些帮助。

以下是本文中使用的代码:

https://files.cnblogs.com/files/powertoolsteam/Promise-Async-Await-main.zip

原文出处:https://www.freecodecamp.org/news/learn-promise-async-await-in-20-minutes/

更多编程相关知识,请访问:编程视频!!

위 내용은 JavaScript에서 Promise 및 Async/Await를 빠르게 학습하세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제