首頁  >  文章  >  web前端  >  探索 JavaScript 中 async 和 wait 的威力

探索 JavaScript 中 async 和 wait 的威力

WBOY
WBOY原創
2023-08-31 15:33:10598瀏覽

探索 JavaScript 中 async 和 wait 的威力

在我之前的教學中,我們介紹了 JavaScript 中 Promise 的基礎知識。我在文章的最後說,promise 允許我們非同步運行我們的程式碼。

在本教程中,我們將學習 JavaScript 中的 asyncawait 關鍵字,它們使我們能夠有效地使用 Promise 並編寫更簡潔的非同步程式碼。

定義 async 函數

讓我們從非同步函數開始討論。考慮以下問候語函數:

function greet() {
  return "Hello, World!";
}

// Outputs: Hello, World!
console.log(greet());

這只是我們之前見過的常規 JavaScript 函數。它所做的只是傳回一個字串,上面寫著「Hello, World!」不過,我們可以將其變成非同步函數,只需在其前面加上async 即可,如下所示:

async function greet() {
  return "Hello, World!";
}

// Outputs: Promise { <state>: "fulfilled", <value>: "Hello, World!" }
console.log(greet());

這次,函數傳回一個 Promise 對象,其 state 屬性設定為已完成,值設定為 Hello, World! 換句話說,promise 已成功解析。

我們仍然回傳字串「Hello, World!」在函數定義裡面。但是,使用 async 關鍵字意味著傳回值將包裝在已解析的 Promise 物件中。已解決的 Promise 的值將與我們從 async 函數傳回的值相同。

您也可以從 async 函數傳回您自己的承諾,如下所示:

async function greet() {
  return Promise.resolve("Hello, World!");
}

// Outputs: Hello, World!
greet().then((value) => console.log(value));

基本上,async 關鍵字幫助我們定義始終傳回承諾的函數。您可以自己明確地傳回一個 Promise,也可以讓函數將任何不是 Promise 的回傳值包裝到 Promise 中。

await 關鍵字

任何 async 函數都可以包含零個或多個 await 表達式。重要的是要記住 await 關鍵字僅在 async 函數內有效。 await 關鍵字用於等待 Promise 解析或拒絕,然後取得已完成的值。

我們使用 await 關鍵字,語法如下:

await expression

表達式可以是原生的Promise,這種情況下直接使用,原生等待。在這種情況下,不會有對 then() 的隱式呼叫。表達式可以是 thenable 對象,在這種情況下,將透過呼叫 then() 方法建構一個新的 Promise 。此表達式也可以是不可thenable 的值。在這種情況下,將建立一個已經實現的 Promise 供我們使用。

假設一個承諾已經兌現了。 async 函數的執行仍然會暫停,直到下一個tick。記住這一點很重要。

以下是在 async 函數中使用 await 關鍵字的範例:

async function greet() {
  let greeting = await "Hello, World!";
  return greeting;
}

// Outputs: [Function: Promise]
console.log(greet().constructor);

// Outputs: Hello, World!
greet().then((msg) => console.log(msg));

這是在明確使用 Promise 時將 await 關鍵字與 async 函數結合使用的另一個範例:

async function greet() {
  let greeting = new Promise((resolve) => {
    setTimeout(() => {
      resolve("Hello, World!");
    }, 2000);
  });
  
  return greeting;
}

// Outputs: [Function: Promise]
console.log(greet().constructor);

// Outputs: Hello, World!
greet().then((msg) => console.log(msg));

這次,我們明確地使用了一個在 2 秒內解析的 Promise。因此,「Hello, World」問候語將在兩秒後列印。

了解語句的執行順序

我們現在將編寫兩個不同的問候函數並查看它們輸出結果的順序。

function n_greet(person) {
  return `Hello, ${person}!`;
}

async function a_greet(person) {
  let greeting = await `Hello, ${person}!`;
  return greeting;
}

我們的第一個函數 n_greet() 是一個傳回字串作為輸出的普通函數。我們的第二個函數是 async 函數,它在 await 關鍵字之後使用表達式。本例中的回傳值是一個已經履行的承諾。

這是呼叫所有這些函數並記錄輸出的程式碼片段:

a_greet("Andrew").then((msg) => console.log(msg));
console.log(n_greet("Adam"));

/* Output in order:
Hello, Adam!
Hello, Andrew! */

問候 Adam 的 n_greet() 函數呼叫已結束。然而,他在輸出中首先受到歡迎。這是因為函數呼叫直接傳回一個字串。

a_greet() 函數呼叫是在開始時向 Andrew 打招呼的,它導致了一個已經履行的承諾的建構。然而,執行仍然暫停,直到下一個時脈週期。這就是為什麼輸出問候語出現在對 Adam 的問候語之後。

現在,我們將定義一個稍微複雜一點的 async 函數,其中包含多個語句。這些語句之一將具有 await 關鍵字。您將看到,在 async 函數中使用 await 關鍵字會暫停執行 await 語句之後的其他語句。

function timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms))    
}

async function aa_greet(person) {
  console.log("Before Await..."); 
  await timeout(2000);
  let greeting = `Hello, ${person}!`;
  console.log("After Await...");
  
  return greeting;
}

我們的 async 函數包含一個明確定義的 Promise,前面有 await 關鍵字。這意味著 await 關鍵字將等待 Promise 被履行,然後傳回已履行的值。該承諾將需要 2 秒才能實現,因此大約 2 秒後我們應該在控制台日誌中看到「After Await...」。

這是程式碼片段,它將記錄我們的 async 函數的一些語句:

console.log("Before Greeting Function...");
aa_greet("Monty").then((msg) => console.log(msg));
console.log("After Greeting Function...");

/* Output in Order
23:42:15.327 Before Greeting Function...
23:42:15.331 Before Await...
23:42:15.331 After Greeting Function...
23:42:17.333 After Await...
23:42:17.333 Hello, Monty! */

首先记录字符串“Before Greeting Function...”,因为这是我们进行的第一次调用。之后,我们调用 aa_greet() 函数。这会导致输出字符串“Before Await...”。然后,浏览器遇到 await 关键字。所以它等待承诺解决。与此同时,aa_greet()函数之外的代码继续执行。这就是为什么我们在下一个日志条目中得到“After Greeting Function...”字符串作为输出。

一旦承诺得到解决,浏览器就会继续执行,我们会得到“After Await...”作为输出。最后,我们解析的问候语作为承诺返回,因为我们使用 async 函数。我们对这个已解决的 Promise 调用 then() 方法并记录“Hello, Monty!”到控制台。

通过 Fetch API 使用 asyncawait

await 关键字的一个常见用例是从远程 API 获取数据。这允许比嵌套回调或承诺链更干净的代码。

async function getData() {
    // use the fetch API to fetch data from an API endpoint
    const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
    
    // check if the response is okay (HTTP status code 200-299)
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }
    
    // parse the response as JSON
    const data = await response.json();
    
    return data;
}

在此函数中,首先我们等待对 API 查询的初始响应。如果响应正常,我们就会等待 JSON 格式的完整响应数据。我们返回 JSON 数据,但请记住,由于这是一个异步函数,因此我们实际上返回一个最终解析为该数据的 Promise。因此,如果您想访问结果数据,您必须再次使用类似await关键字的东西!

const data = await getData();

最终想法

在上一篇教程中了解了 Promise 对象后,我们在本教程中讨论了 async 函数和 await 关键字。您现在应该能够编写自己的 async 函数,使用 await 关键字来使用更清晰、更易读的代码实现基于 Promise 的行为。

以上是探索 JavaScript 中 async 和 wait 的威力的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn