Maison > interface Web > js tutoriel > Apprenez rapidement Promise et Async/Await en JavaScript

Apprenez rapidement Promise et Async/Await en JavaScript

青灯夜游
Libérer: 2021-01-30 10:01:05
avant
1514 Les gens l'ont consulté

Apprenez rapidement Promise et Async/Await en JavaScript

Généralement en développement, l'interrogation des opérations de l'API réseau prend souvent du temps, ce qui signifie qu'il peut prendre un certain temps pour attendre une réponse. Par conséquent, afin d’éviter la situation dans laquelle le programme ne répond plus lorsqu’il est demandé, la programmation asynchrone est devenue une compétence de base pour les développeurs.

Lorsqu'il s'agit d'opérations asynchrones en JavaScript, nous entendons généralement le concept de « Promesse ». Mais comprendre comment il fonctionne et comment l’utiliser peut être abstrait et difficile à comprendre.

Recommandations associées : "Tutoriel vidéo javascript"

Ensuite, dans cet article, nous utiliserons des méthodes pratiques pour vous aider à comprendre plus rapidement leurs concepts et leur utilisation, donc contrairement à beaucoup tutoriels secs traditionnels, nous commencerons par les quatre exemples suivants :

  • Exemple 1 : Expliquer les bases de Promise avec les anniversaires
  • Exemple 2 : un jeu de devinettes
  • Exemple 3 : Obtenir des informations sur le pays à partir de l'API Web
  • Exemple 4 : Obtenir une liste des pays voisins d'un pays à partir de l'API Web

Exemple 1 : Utiliser les anniversaires pour expliquer les bases de Promise

Tout d'abord, jetons un coup d'œil à la forme de base de Promise.

La promesse a trois états une fois exécutée : en attente (exécution), remplie (réussite) et rejetée (échec).

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完成时,无论如何都会执行的情况
})
Copier après la connexion

L'introduction du formulaire de base est terminée, commençons donc par examiner les exemples suivants.

User Story : Mon amie Kayo a promis de me préparer un gâteau pour ma fête d'anniversaire dans deux semaines.

Si tout se passe bien et que Kayo ne tombe pas malade, nous aurons une certaine quantité de gâteau, mais si Kayo tombe malade, nous n'aurons pas de gâteau. Mais avec ou sans gâteau, nous organiserons quand même une fête d'anniversaire.

Donc, pour cet exemple, nous traduisons l'histoire de fond ci-dessus en code JS. Tout d'abord, créons une fonction qui renvoie une promesse.

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

En JavaScript, nous pouvons utiliser new Promise() pour créer une nouvelle Promise, qui accepte une fonction avec les paramètres : (resolve, rejet)=>{}.

Dans cette fonction, résoudre et rejeter sont des fonctions de rappel fournies par défaut. Examinons de plus près le code ci-dessus.

Quand nous exécutons la fonction onMyBirthday 2000 ms plus tard.

  • Si Kayo n'est pas malade, alors nous exécutons la fonction de résolution avec 2 comme paramètre
  • Si Kayo est malade, alors nous l'exécutons avec une nouvelle erreur ("Je suis triste" ) comme paramètre de rejet. Bien que vous puissiez transmettre tout ce que vous souhaitez rejeter en tant que paramètre, il est recommandé de lui transmettre un objet Error.

Maintenant, parce que onMyBirthday() renvoie une promesse, nous avons accès aux méthodes then, catch et enfin. Nous pouvons également accéder aux paramètres transmis pour résoudre et rejeter plus tôt et intercepter l'utilisation des paramètres transmis pour résoudre et rejeter.

Comprenons le concept à travers le code suivant

Si Kayo n'est pas malade

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

Si Kayo est malade

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

Je crois que vous pouvez comprendre Promesse à travers cet exemple Concepts de base.

Commençons par l'exemple 2

Exemple 2 : Un jeu de devinettes

Besoins de base :

  • Utilisateur Vous pouvez entrez n'importe quel nombre
  • Le système génère aléatoirement un nombre de 1 à 6
  • Si l'utilisateur saisit un nombre égal au nombre aléatoire du système, l'utilisateur recevra 2 points
  • Si l'utilisateur saisit un nombre S'il y a une différence de 1 par rapport au nombre aléatoire du système, l'utilisateur recevra 1 point, sinon, l'utilisateur recevra 0 point
  • L'utilisateur peut jouer tant que ils veulent

Pour les exigences ci-dessus, nous créons d'abord une fonction enterNumber et renvoie une promesse :

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    // 从这开始编码
  });
};
Copier après la connexion

La première chose que nous faisons est de demander un numéro à l'utilisateur et de sélectionner au hasard un nombre entre 1 et 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的随机数
  });
};
Copier après la connexion

Lorsque l'utilisateur saisit une valeur qui n'est pas un nombre. Dans ce cas, nous appelons la fonction de rejet et renvoyons l'erreur :

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函数
    }
  });
};
Copier après la connexion

Ensuite, nous devons vérifier si userNumber est égal à RanomNumber, s'il est égal, nous donnons 2 points à l'utilisateur, puis nous pouvons exécuter la fonction de résolution pour transmettre un objet { points : 2, randomNumber }.

Si la différence entre userNumber et randomNumber est de 1, alors nous donnons à l'utilisateur 1 point. Sinon, nous donnons 0 point à l’utilisateur.

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,
    });
  }
});
Copier après la connexion

Ensuite, créons une autre fonction pour demander à l'utilisateur s'il souhaite continuer le jeu :

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

Afin de ne pas forcer la fin du jeu, la Promesse que nous avons créée n'utilise pas le Rejeter le rappel.

Ci-dessous, nous créons une fonction pour gérer la logique de devinette :

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 函数
Copier après la connexion

在这当我们调用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);
  }
};
Copier après la connexion

通过在函数前使用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 函数
Copier après la connexion

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

示例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();
Copier après la connexion

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

示例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);
  }
};
Copier après la connexion

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

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

  console.log(china);
};

fetchCountryAndNeighbors();
Copier après la connexion

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

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

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

const neighbors = 
    china.borders.map((border) => fetchCountry(border));
Copier après la connexion

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();
Copier après la connexion

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

以下是示例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();
Copier après la connexion

总结

完成这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/

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:cnblogs.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal