日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

async function_掌握 Async/Await

發布時間:2025/4/5 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 async function_掌握 Async/Await 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

摘要: 還不用Async/Await就OUT了。。

  • 原文:掌握 Async/Await
  • 作者:Jartto

Fundebug經授權轉載,版權歸原作者所有。

前端工程師肯定都經歷過 JS 回調鏈獄的痛苦過程,我們在使用 Promise 的時候總是不盡人意。這時候 Async/Await 應運而生,它到底有什么魔力,我們來說道說道。

一、回顧 Promise

所謂 Promise,簡單說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。

1. 語法

new Promise(executor); new Promise(function(resolve, reject) { ... });

2. 參數

帶有 resolve 、reject 兩個參數的一個函數。這個函數在創建 Promise 對象的時候會立即得到執行(在 Promise 構造函數返回 Promise 對象之前就會被執行),并把成功回調函數(resolve)和失敗回調函數(reject)作為參數傳遞進來。調用成功回調函數(resolve)和失敗回調函數(reject)會分別觸發 Promise 的成功或失敗。

這個函數通常被用來執行一些異步操作,操作完成以后可以選擇調用成功回調函數(resolve)來觸發 Promise 的成功狀態,或者,在出現錯誤的時候調用失敗回調函數(reject)來觸發 Promise 的失敗。

3. Promise.all

用 Promise.all 來執行,all 接收一個數組參數,里面的值最終都算返回 Promise 對象。這樣,三個異步操作的并行執行的,等到它們都執行完后才會進到 then 里面。

Promise.all([async1(), async2(), async3()]) .then(function(results){console.log(results); });

all 會把所有異步操作的結果放進一個數組中傳給 then,就是上面的 results。

4. Promise.race

all 方法的效果實際上是「誰跑的慢,以誰為準執行回調」,那么相對的就有另一個方法「誰跑的快,以誰為準執行回調」,這就是 race方法:

Promise.race([requestImg(), timeout()]) .then(function(results){console.log(results); }) .catch(function(reason){console.log(reason); });

上述代碼演示了 race 的基本用法,實現的功能是:請求圖片,如果請求成功就返回圖片,否則就調用超時函數。

更多資源,請查看:

  • js promise
  • 白話 promise
  • promise 對象-阮一峰
  • promise

二、Promise 為何不完美?

乍一看,Promise 還不錯,幫我們解決了回調鏈獄的問題。當然這只是簡單使用,碰到復雜的業務也有很雞肋的場景,比如:

1. 錯誤處理

在下面的 Promise 示例中,Try/Catch 不能處理 JSON.parse 的錯誤,因為它在 Promise中。我們需要使用 catch,這樣錯誤處理代碼非常冗余。并且,在我們的實際生產代碼會更加復雜。

const makeRequest = () => {try {getJSON().then(result => {// JSON.parse可能會出錯const data = JSON.parse(result)console.log(data)})// 取消注釋,處理異步代碼的錯誤// .catch((err) => {// console.log(err)// })} catch (err) {console.log(err)} }

Async/Await 讓 Try/Catch 可以同時處理同步和異步錯誤。使用 Async/Await 的話,Catch能處理 JSON.parse 錯誤:

const makeRequest = async () => {try {// this parse may failconst data = JSON.parse(await getJSON())console.log(data)} catch (err) {console.log(err)} }

Async/Await 最讓人舒服的一點是代碼看起來是同步的。

2. 條件語句

下面示例中,需要獲取數據,然后根據返回數據決定是直接返回,還是繼續獲取更多的數據。

const makeRequest = () => {return getJSON().then(data => {if (data.needsAnotherRequest) {return makeAnotherRequest(data).then(moreData => {console.log(moreData)return moreData})} else {console.log(data)return data}}) }

這些代碼看著就頭痛。嵌套(6層),括號,return 語句很容易讓人感到迷茫,而它們只是需要將最終結果傳遞到最外層的Promise。如果換成 Async/Await 呢:

const makeRequest = async () => {const data = await getJSON();if (data.needsAnotherRequest) {const moreData = await makeAnotherRequest(data);console.log(moreData);return moreData;} else {console.log(data);return data; } }

所以,這才是真正擺脫回調鏈獄的正確做法。

3. 中間值

你很可能遇到過這樣的場景,調用 promise1,使用 promise1 返回的結果去調用 promise2,然后使用兩者的結果去調用promise3。你的代碼很可能是這樣的:

const makeRequest = () => {return promise1().then(value1 => {return promise2(value1);.then(value2 => { return promise3(value1, value2);})}) } // 或者: const makeRequest = () => {return promise1().then(value1 => {return Promise.all([value1, promise2(value1)])}).then(([value1, value2]) => { return promise3(value1, value2)}) }

怎么寫都會覺得很復雜,那如果 Async/Await 用來實現呢,表現可能如下:

const makeRequest = async () => {const value1 = await promise1();const value2 = await promise2(value1);return promise3(value1, value2); }

是不是很 6 ,將復雜的場景簡化,這樣的代碼就很有靈性了。

4. 錯誤棧

調用了多個 Promise,假設 Promise 鏈中某個地方拋出了一個錯誤,Promise 鏈中返回的錯誤棧沒有給出錯誤發生位置的線索。更糟糕的是,它會誤導我們;錯誤棧中唯一的函數名為 callAPromise,然而它和錯誤沒有關系。(文件名和行號還是有用的)。

const makeRequest = () => {return callAPromise().then(() => callAPromise()).then(() => callAPromise()).then(() => callAPromise()).then(() => callAPromise()).then(() => {throw new Error("oops");}) }makeRequest().catch(err => {console.log(err);// output// Error: oops at callAPromise.then.then.then.then.then (index.js:8:13) })

然而,Async/Await 中的錯誤棧會指向錯誤所在的函數:

const makeRequest = async () => {await callAPromise();await callAPromise();await callAPromise();throw new Error("oops"); }makeRequest().catch(err => {console.log(err);// output// Error: oops at makeRequest (index.js:7:9) })

5. 調試

調試 Promise 有兩個問題:

  • 不能在返回表達式的箭頭函數中設置斷點;
  • 如果你在 then 代碼塊中設置斷點,調試器不會跳到下一個 then,因為它只會跳過異步代碼;

而使用 Await/Async 時,你不再需要那么多箭頭函數,這樣你就可以像調試同步代碼一樣跳過 Await 語句。

這里只簡單的列出問題,詳細請查看原文:Async/Await 替代 Promise 的 6 個理由

三、新時代的曙光 Async/Await

簡單介紹:

  • Await/Async 是寫異步代碼的新方式,以前的方法有回調函數和 Promise。
  • Await/Async 是基于 Promise 實現的,它不能用于普通的回調函數。
  • Await/Async 與 Promise 一樣,是非阻塞的。
  • Await/Async 使得異步代碼看起來像同步代碼,這正是它的魔力所在。

使用 Promise 是這樣的:

const jarttoDemo = () => getJSON().then(data => {return data; })jarttoDemo();

使用 Async/Await 是這樣的:

const jarttoDemo = async () => {let data = await getJSON();return data; }jarttoDemo();

基本規則:

  • Async 表示這是一個 Async 函數,Await 只能用在這個函數里面。
  • Await 表示在這里等待 Promise返回結果了,再繼續執行。
  • Await 后面跟著的應該是一個 Promise 對象,當然,其他返回值也沒關系,只是會立即執行,不過那樣就沒有意義了。

四、更多用法示例

1. 簡單示例

var sleep = function (time) {return new Promise(function (resolve, reject) {setTimeout(function () {resolve();}, time);}) };var start = async function () {// 在這里使用起來就像同步代碼那樣直觀console.log('start');await sleep(3000);console.log('end'); };start();

2. 獲得返回值

var sleep = function (time) {return new Promise(function (resolve, reject) {setTimeout(function () {// 返回 ‘ok’resolve('ok');}, time);}) };var start = async function () {let result = await sleep(3000);console.log(result); // 收到 ‘ok’ };

3. 錯誤捕獲

const makeRequest = async () => {try {// this parse may failconst data = JSON.parse(await getJSON())console.log(data)} catch (err) {console.log(err)} }

既然 then 不用寫了,那么 catch 也不用寫,可以直接用標準的 try catch 語法捕捉錯誤。

var sleep = function (time) {return new Promise(function (resolve, reject) {setTimeout(function () {// 模擬出錯了,返回 ‘error’reject('error');}, time);}) };var start = async function () {try {console.log('start');await sleep(3000); // 這里得到了一個返回錯誤// 所以以下代碼不會被執行了console.log('end');} catch (err) {console.log(err); // 這里捕捉到錯誤 `error`} };

4. 條件語句

Promise 寫法:

const makeRequest = () => {return getJSON().then(data => {if (data.needsAnotherRequest) {return makeAnotherRequest(data).then(moreData => {return moreData;})} else {return data;}}) }

Async/Await 寫法:

const makeRequest = async () => {const data = await getJSON();if (data.needsAnotherRequest) {const moreData = await makeAnotherRequest(data);return moreData;} else {return data; } }

5. 循環多個 Await

var start = async function () {for (let i = 1; i <= 10; i++) {console.log(`當前是第 ${i} 次等待..`);await sleep(1000);} };

需要注意的是,Await 必須在 Async 函數的上下文中的。

6. 在 forEach 中使用

async function printFiles() {const files = await getFilePaths();for (let file of files) {const contents = await fs.readFile(file, "utf8");console.log(contents);} }async function printFiles() {const files = await getFilePaths();await Promise.all(files.map(file => {return async () => {const contents = await fs.readFile(file, "utf8");console.log(contents);};})); }

示例參考如下文章:

  • Async/Await替代Promise的6個理由
  • ES7 的 Async/Await
  • Using async/await with a forEach loop

五、總結

我們一直在強調代碼的可讀性和可維護性,對我來說,Async/Await 更加易懂和易用。所以,不管是 Promise 還是 Async/Await ,能解決實際問題的技術就是好技術。

當然,Async/Await 也是基于 Promise 概念的,技術上我們也可以求同存異,不必太過較真。一句話,選擇權在你!

總結

以上是生活随笔為你收集整理的async function_掌握 Async/Await的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。