這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 async await 語法是 ES7出現的,是基於ES6的 promise和generator實現的 generator函數 在之前我專門講個generator的使用與原理實現,大家沒瞭解過的可以先看那個手寫generator核心 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
前言
async await 語法是 ES7出現的,是基於ES6的 promise和generator實現的
generator函數
在之前我專門講個generator的使用與原理實現,大家沒瞭解過的可以先看那個手寫generator核心原理,再也不怕面試官問我generator原理
這裡就不再贅述generator,專門的文章講專門的內容。
await在等待什麼
我們先看看下麵這代碼,這是async await的最簡單使用,await後面返回的是一個Promise對象:
async function getResult() { await new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) } getResult()
但不知你有沒有想過一個問題,為什麼會等到返回的promise的對象的狀態為非pending的時候才會繼續往下執行,也就是resolve執行之後,才會繼續執行,就像下麵的代碼一樣
async function getResult() { await new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) console.log(2); } getResult()
可以看到運行結果是先列印了1,再列印2了,也就是說明在返回的promise對象沒執行resolve()前,就一直在await,等它執行。然後再執行下麵的程式,那這個是怎麼實現的呢?
原理實現
我們看一下下麵的代碼,輸出順序是什麼?
async function getResult() { await new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) await new Promise((resolve, reject) => { setTimeout(() => { resolve(2); console.log(2); }, 500); }) await new Promise((resolve, reject) => { setTimeout(() => { resolve(3); console.log(3); }, 100); }) } getResult()
沒錯是 1,2,3.
那用generator函數專門來實現這個效果呢
我一開始這樣來實現:
function* getResult(params) { yield new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(2); console.log(2); }, 500); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(3); console.log(3); }, 100); }) } const gen = getResult() gen.next(); gen.next(); gen.next();
但是發現列印順序是 3,2,1.明顯不對。
這裡的問題主要是三個 new Promise幾乎是同一時刻執行了。才會出現這種問題,所以需要等第一個promise執行完resolve之再執行下一個,所以要這麼實現
function* getResult(params) { yield new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(2); console.log(2); }, 500); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(3); console.log(3); }, 100); }) } const gen = getResult() gen.next().value.then(() => { gen.next().value.then(() => { gen.next(); }); });
可以看到這樣就列印正常了。
特別 需要解釋下。gen.next().value 就是返回的promise對象,不理解的可以看看文首介紹的那篇generator的 文章。手寫generator核心原理,再也不怕面試官問我generator原理
優化
但是呢,總不能有多少個await,就要自己寫多少個嵌套吧,所以還是需要封裝一個函數,顯然,遞歸實現最簡單
function* getResult(params) { yield new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(2); console.log(2); }, 500); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(3); console.log(3); }, 100); }) } const gen = getResult() function co(g) { g.next().value.then(()=>{ co(g) }) } co(gen)
再來看看列印結果
可以發現成功執行了,但是為什麼報錯了?
這是因為generator方法會返回四次,最後一次的value是undefined。
而實際上返回第三次就表示已經返回done,代表結束了,所以,我們需要判斷是否是已經done了,不再讓它繼續遞歸
所以可以改成這樣
function* getResult(params) { yield new Promise((resolve, reject) => { setTimeout(() => { resolve(1); console.log(1); }, 1000); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(2); console.log(2); }, 500); }) yield new Promise((resolve, reject) => { setTimeout(() => { resolve(3); console.log(3); }, 100); }) } const gen = getResult() function co(g) { const nextObj = g.next(); if (nextObj.done) { return; } nextObj.value.then(()=>{ co(g) }) } co(gen)
可以看到這樣就實現了。
完美,這個co其實也是大名鼎鼎的co函數的簡單寫法
本篇文章關於async 和 await的原理揭秘就到此為止了,再講下去就不禮貌了。