Heim  >  Artikel  >  Web-Frontend  >  Lernen Sie schnell Promise und Async/Await in JavaScript

Lernen Sie schnell Promise und Async/Await in JavaScript

青灯夜游
青灯夜游nach vorne
2021-01-30 10:01:051445Durchsuche

Lernen Sie schnell Promise und Async/Await in JavaScript

Im Allgemeinen ist das Abfragen von Netzwerk-API-Vorgängen in der Entwicklung oft zeitaufwändig, was bedeutet, dass es eine Weile dauern kann, bis man eine Antwort erhält. Um zu vermeiden, dass das Programm auf Anfrage nicht mehr reagiert, ist die asynchrone Programmierung daher zu einer Grundkompetenz für Entwickler geworden.

Beim Umgang mit asynchronen Vorgängen in JavaScript hören wir normalerweise den Begriff „Promise“. Aber zu verstehen, wie es funktioniert und wie man es nutzt, kann abstrakt und schwer zu verstehen sein.

Verwandte Empfehlungen: „Javascript-Video-Tutorial

In diesem Artikel werden wir praktische Methoden verwenden, um Ihnen zu helfen, ihre Konzepte und Verwendung schneller zu verstehen, sodass sie sich von vielen herkömmlichen trockenen Tutorials unterscheiden. Wir beginnen mit die folgenden vier Beispiele:

  • Beispiel 1: Erklären der Grundlagen von Promise mit Geburtstagen
  • Beispiel 2: Ein Ratespiel
  • Beispiel 3: Abrufen von Länderinformationen von einer Web-API
  • Beispiel 4: Von Holen Sie sich eine Liste der Nachbarländer eines Landes in der Web-API

Beispiel 1: Verwenden Sie Geburtstag, um die Grundlagen von Promise zu erklären

Werfen wir zunächst einen Blick auf die Grundform von Promise.

Versprechen wird bei der Ausführung in drei Zustände unterteilt: ausstehend (wird ausgeführt), erfüllt (erfolgreich) und abgelehnt (fehlgeschlagen).

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

Die Einführung in die Grundform ist abgeschlossen, also schauen wir uns zunächst die folgenden Beispiele an.

Benutzergeschichte: Mein Freund Kayo hat versprochen, mir in zwei Wochen einen Kuchen für meine Geburtstagsfeier zu backen.

Wenn alles gut geht und Kayo nicht krank wird, bekommen wir eine bestimmte Menge Kuchen, aber wenn Kayo krank wird, bekommen wir keinen Kuchen. Aber ob mit oder ohne Kuchen, wir werden trotzdem eine Geburtstagsfeier veranstalten.

Für dieses Beispiel übersetzen wir also die obige Hintergrundgeschichte in JS-Code. Erstellen wir zunächst eine Funktion, die ein Versprechen zurückgibt.

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

In JavaScript können wir new Promise() verwenden, um ein neues Promise zu erstellen, das eine Funktion mit den Parametern akzeptiert: (auflösen, abweisen)=>{}.

In dieser Funktion sind Auflösen und Ablehnen die standardmäßig bereitgestellten Rückruffunktionen. Schauen wir uns den obigen Code genauer an.

Wenn wir die Funktion onMyBirthday 2000 ms später ausführen.

  • Wenn Kayo nicht krank ist, führen wir die Auflösungsfunktion mit 2 als Parameter aus.
  • Wenn Kayo krank ist, verwenden wir den neuen Fehler („Ich bin traurig“) als Parameter, um die Ablehnung auszuführen. Obwohl Sie alles, was Sie ablehnen möchten, als Parameter übergeben können, wird empfohlen, ihm ein Error-Objekt zu übergeben.

Da onMyBirthday() nun ein Promise zurückgibt, haben wir Zugriff auf die Methoden then, Catch und Finally. Wir haben auch Zugriff auf die Parameter, die früher zum Auflösen und Zurückweisen übergeben wurden, und können sie verwenden.

Lassen Sie uns das Konzept anhand des folgenden Codes verstehen

Wenn Kayo nicht krank ist

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

Wenn Kayo krank ist

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

Ich glaube, Sie können das Grundkonzept von Promise anhand dieses Beispiels verstehen. Wir beginnen mit Beispiel 2 eine Zahl Wenn sie gleich der Zufallszahl des Systems ist, erhält der Benutzer 2 Punkte erhält 0 Punkte

Der Benutzer kann so lange spielen, wie er möchte

Für die oben genannten Anforderungen erstellen wir zunächst eine enterNumber-Funktion und geben ein Versprechen zurück:
const enterNumber = () => {
  return new Promise((resolve, reject) => {
    // 从这开始编码
  });
};

Als Erstes fragen wir den Benutzer nach einer Nummer und wählen Sie zufällig eine Zahl zwischen 1 und 6 aus:

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的随机数
  });
};

Wenn der Benutzer eine Zahl eingibt, die nicht der Wert der Zahl ist. In diesem Fall rufen wir die Ablehnungsfunktion auf und geben den Fehler aus:
    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函数
        }
      });
    };
  • Als nächstes müssen wir prüfen, ob userNumber gleich RanomNumber ist. Wenn gleich, geben wir dem Benutzer 2 Punkte und können dann die Auflösungsfunktion ausführen Übergeben Sie ein Objekt {points: 2, randomNumber }.
  • Wenn die Differenz zwischen userNumber und randomNumber 1 beträgt, dann geben wir dem Benutzer 1 Punkt. Ansonsten geben wir dem Nutzer 0 Punkte.
  • 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,
        });
      }
    });
  • Als nächstes erstellen wir eine weitere Funktion, um den Benutzer zu fragen, ob er das Spiel fortsetzen möchte:
  • const continueGame = () => {
      return new Promise((resolve) => {
        if (window.confirm("Do you want to continue?")) { // 向用户询问是否要继续游戏
          resolve(true);
        } else {
          resolve(false);
        }
      });
    };
  • Um das Ende des Spiels nicht zu erzwingen, verwendet das von uns erstellte Promise nicht den Reject-Rückruf.
  • Nachfolgend erstellen wir eine Funktion zur Handhabung der Schätzlogik:
  • 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/

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

Das obige ist der detaillierte Inhalt vonLernen Sie schnell Promise und Async/Await in JavaScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen