async? es7???. async ? wait? ES7? ?? ??? ???? ??? ??? ?? ??????. async/await? ?? ?? ? ??? ??? ?? ?? ????? ? ? ???, ? ??? ??? js ??? ??? ?????. ???? ? ? ??? async? "???"? ?????. async? async? wait ??? ??? ??? ??? ???? ? ????, wait? ??? ???? ??? ? ????.
? ????? ?? ??: Windows 7 ???, ECMAScript ?? 6, Dell G3 ???.
ES7(ES2017)?? ??? ????? ??? ??: async, wait.
async/await? ??????
async ? wait? ??? ??? ?? ???? ?? ?? ?? ? ??? ??? ?? ?? ????? ? ? ????. ?? ??? ????? js ??? ??? ?????.
async? ???? ? ? ??? "???"? ?????. async? ??? ????? ???? ? ?????. ??? wait? ?? ??? "??"? ???? ??? ??? ???? ? ?????.
Async? Wait?? ??? ??? ????. ? ? ?? ??? ? ? ????. ??? Wait? ??? ???? ??? ? ????.
co ??? ??? ???? co ??? Master TJ? ??? ??? ???? ??? ????? ???? ?? ??? ????? ?? ??? ???. ??? ??? ????? ? ? ????. Async/await? co ??? ????????. ???? ??? ?? ???? ???? ??? ? ?? co ??? ???? ????. ??? async? Promise? ?????.
?? ???? ? ?, co ???? async/await?? Promise? ?? ???? ??? ?????. Promise? ?? ? ??? ???? ?? Promise? ?? ??? ??? ? ????.
Compare Promise, co, async/await
????? ??? ?? ???? ? ?? ?? ?? ???, ??? ? ???? ?????.
mongodb? nodejs ????? ???? mongodb ??????? ???? ??? mongodb? js ????? ????? Promise ??? ???? ??? Promise? ??? ??? ??? ?? ?????.
Promise ?? ??
MongoClient.connect(url + db_name).then(db => { return db.collection('blogs'); }).then(coll => { return coll.find().toArray(); }).then(blogs => { console.log(blogs.length); }).catch(err => { console.log(err); })
Promise? then() ???? ?? Promise? ???? ?? ??? ? ???, ???? ?? ???? Promise? ??????. ?? ??? db.collection()? ???? ?, ? ??? ??? ????? ?? Promise? ???? ?? then() ???? ???? ?????. ?? ???? Promise ??? ?????. ?? ?????? MongoClient.connect()? ???? Promise? ??? ?? then() ????? ?????? ?? db? ?? ?? coll ??? ??? ?????. ?? then() ????? coll ??? ?? ? ??? ???? ?? ??? ??? ?? ???? then() ???? ???? Promise ??? ?????. ? Promise ????? ???? ??? ???? ?? catch()? ?? ?????. Promise Chain? ???? ??? ? ??? ?? ??? ???? ???? ??? ? ???? ????? ? ????? ?? ? ????. ?? ?????? ??? ??? ?? ??? ??? ??? ?? ????? ???? ?????. ??? ???? ?? "???" ??? ????. ?, ? then() ????? ?? ??? ?? then() ????? ??? ????? ????. ?? ???? ?? ???? ? ????. ??? ???? ?? ? ??(blogs => {})??? ?? ?? ???? ?? ? ??? ?? db ??? coll ??? ??? ? ??? ????. ??, ??? ??? ??? ? db.close() ??????? ?? ??? ??? ?? ???? ?? ???? ? ??? ????.
? ??? then() ??? ???? ????. ?? ??? ??? ???? ??? Promise ??? ?? ??????.
MongoClient.connect(url + db_name).then(db => { let coll = db.collection('blogs'); coll.find().toArray().then(blogs => { console.log(blogs.length); db.close(); }).catch(err => { console.log(err); }); }).catch(err => { console.log(err); })
???? ? ?? Promise? ???? ??? ?? ???? ?? db ??? ??? ? ????. ??? ? ??? ???? ????. ??? ?????. ? ??? ?? ?? ???? ?? ??? Promise ?? ???? ???? ?????.
?? Promise? ??? ???? ?? ??? ? Promise? ??? ??? ???.
? then() ???? db? ???? ? ?? ??? ????.
MongoClient.connect(url + db_name).then(db => { return {db:db,coll:db.collection('blogs')}; }).then(result => { return {db:result.db,blogs:result.coll.find().toArray()}; }).then(result => { return result.blogs.then(blogs => { //注意這里,result.coll.find().toArray()返回的是一個(gè)Promise,因此這里需要再解析一層 return {db:result.db,blogs:blogs} }) }).then(result => { console.log(result.blogs.length); result.db.close(); }).catch(err => { console.log(err); });
? then() ???? ???? ??? ?? db? ?? ??? ?? ???? ?????. ? ??? ???? ??? ???? Promise ?? ?? ? Promise?? ?? ?? ?? ??? ?????.
?? ?? ?? ??? ? ?? then() ????? ??? {db:result.db,blogs:result.coll.find().toArray()}
對(duì)象中,blogs
? Promise???. ?? then() ?????? ??? ?? ?? ?? ?? ??? ? ???? then()? ???? ???. ?? ??? ???? ?? ??? ?? ? ?? ??? ?? db? blogs? ?????. ???? Promise? ??? ????? Promise? then()? ? ??? ?????.
這種方式,也是很蛋疼的一個(gè)方式,因?yàn)槿绻龅絫hen()方法中返回的不是同步的值,而是Promise的話,我們需要多做很多工作。而且,每次都透?jìng)饕粋€(gè)“多余”的db對(duì)象,在邏輯上也有點(diǎn)冗余。
但除此之外,對(duì)于Promise鏈的使用,如果遇到上面的問(wèn)題,好像也沒(méi)其他更好的方法解決了。我們只能根據(jù)場(chǎng)景去選擇一種“最優(yōu)”的方案,如果要使用Promise鏈的話。
鑒于Promise上面蛋疼的問(wèn)題,TJ大神將ES6中的生成器函數(shù),用co模塊包裝了一下,以更優(yōu)雅的方式來(lái)解決上面的問(wèn)題。
co搭配生成器函數(shù)
如果使用co模塊搭配生成器函數(shù),那么上面的例子可以改寫(xiě)如下:
const co = require('co'); co(function* (){ let db = yield MongoClient.connect(url + db_name); let coll = db.collection('blogs'); let blogs = yield coll.find().toArray(); console.log(blogs.length); db.close(); }).catch(err => { console.log(err); });
co是一個(gè)函數(shù),將接受一個(gè)生成器函數(shù)作為參數(shù),去執(zhí)行這個(gè)生成器函數(shù)。生成器函數(shù)中使用yield
關(guān)鍵字來(lái)“同步”獲取每個(gè)異步操作的值。
上面代碼在代碼形式上,比上面使用Promise鏈要優(yōu)雅,我們消滅了回調(diào)函數(shù),代碼看起來(lái)都是同步的。除了使用co和yield有點(diǎn)怪之外。
使用co模塊,我們要將所有的操作包裝成一個(gè)生成器函數(shù),然后使用co()去調(diào)用這個(gè)生成器函數(shù)。看上去也還可以接受,但是ES的進(jìn)化是不滿足于此的,于是async/await被提到了ES7的提案。
async/await
我們先看一下使用async/await改寫(xiě)上面的代碼:
(async function(){ let db = await MongoClient.connect(url + db_name); let coll = db.collection('blogs'); let blogs = await coll.find().toArray(); console.log(blogs.length); db.close(); })().catch(err => { console.log(err); });
我們對(duì)比代碼可以看出,async/await和co兩種方式代碼極為相似。co換成了async,yield換成了await。同時(shí)生成器函數(shù)變成了普通函數(shù)。這種方式在語(yǔ)義上更加清晰明了,async表明這個(gè)函數(shù)是異步的,同時(shí)await表示要“等待”異步操作返回值。
async函數(shù)返回一個(gè)Promise,上面的代碼其實(shí)是這樣:
let getBlogs = async function(){ let db = await MongoClient.connect(url + db_name); let coll = db.collection('blogs'); let blogs = await coll.find().toArray(); db.close(); return blogs; }; getBlogs().then(result => { console.log(result.length); }).catch(err => { console.log(err); })
我們定義getBlogs為一個(gè)async函數(shù),最后返回得到的博客列表最終會(huì)被包裝成一個(gè)Promise返回,如上,我們直接調(diào)用getBlogs().then()方法可獲取async函數(shù)返回值。
好了,上面我們簡(jiǎn)單對(duì)比了一下三種解決異步方案,下面我們來(lái)深入了解一下async/await。
深入async/await
async返回值
async用于定義一個(gè)異步函數(shù),該函數(shù)返回一個(gè)Promise。
如果async函數(shù)返回的是一個(gè)同步的值,這個(gè)值將被包裝成一個(gè)理解resolve的Promise,等同于return Promise.resolve(value)
。
await用于一個(gè)異步操作之前,表示要“等待”這個(gè)異步操作的返回值。await也可以用于一個(gè)同步的值。
//返回一個(gè)Promise let timer = async function timer(){ return new Promise((resolve,reject) => { setTimeout(() => { resolve('500'); },500); }); } timer().then(result => { console.log(result); //500 }).catch(err => { console.log(err.message); });
//返回一個(gè)同步的值 let sayHi = async function sayHi(){ let hi = await 'hello world'; return hi; //等同于return Promise.resolve(hi); } sayHi().then(result => { console.log(result); });
上面這個(gè)例子返回是一個(gè)同步的值,字符串’hello world’,sayHi()是一個(gè)async函數(shù),返回值被包裝成一個(gè)Promise,可以調(diào)用then()方法獲取返回值。對(duì)于一個(gè)同步的值,可以使用await,也可以不使用await。效果效果是一樣的。具體用不用,看情況。
比如上面使用mongodb查詢博客那個(gè)例子,let coll = db.collection('blogs');
,這里我們就沒(méi)有用await,因?yàn)檫@是一個(gè)同步的值。當(dāng)然,也可以使用await,這樣會(huì)顯得代碼統(tǒng)一。雖然效果是一樣的。
async函數(shù)的異常
let sayHi = async function sayHi(){ throw new Error('出錯(cuò)了'); } sayHi().then(result => { console.log(result); }).catch(err => { console.log(err.message); //出錯(cuò)了 });
我們直接在async函數(shù)中拋出一個(gè)異常,由于返回的是一個(gè)Promise,因此,這個(gè)異常可以調(diào)用返回Promise的catch()方法捕捉到。
和Promise鏈的對(duì)比:
我們的async函數(shù)中可以包含多個(gè)異步操作,其異常和Promise鏈有相同之處,如果有一個(gè)Promise被reject()那么后面的將不會(huì)再進(jìn)行。
let count = ()=>{ return new Promise((resolve,reject) => { setTimeout(()=>{ reject('故意拋出錯(cuò)誤'); },500); }); } let list = ()=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve([1,2,3]); },500); }); } let getList = async ()=>{ let c = await count(); let l = await list(); return {count:c,list:l}; } console.time('begin'); getList().then(result => { console.log(result); }).catch(err => { console.timeEnd('begin'); console.log(err); }); //begin: 507.490ms //故意拋出錯(cuò)誤
如上面的代碼,定義兩個(gè)異步操作,count和list,使用setTimeout延時(shí)500毫秒,count故意直接拋出異常,從輸出結(jié)果來(lái)看,count()拋出異常后,直接由catch()捕捉到了,list()并沒(méi)有繼續(xù)執(zhí)行。
并行
使用async后,我們上面的例子都是串行的。比如上個(gè)list()和count()的例子,我們可以將這個(gè)例子用作分頁(yè)查詢數(shù)據(jù)的場(chǎng)景。先查詢出數(shù)據(jù)庫(kù)中總共有多少條記錄,然后再根據(jù)分頁(yè)條件查詢分頁(yè)數(shù)據(jù),最后返回分頁(yè)數(shù)據(jù)以及分頁(yè)信息。
我們上面的例子count()和list()有個(gè)“先后順序”,即我們先查的總數(shù),然后又查的列表。其實(shí),這兩個(gè)操作并無(wú)先后關(guān)聯(lián)性,我們可以異步的同時(shí)進(jìn)行查詢,然后等到所有結(jié)果都返回時(shí)再拼裝數(shù)據(jù)即可。
let count = ()=>{ return new Promise((resolve,reject) => { setTimeout(()=>{ resolve(100); },500); }); } let list = ()=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve([1,2,3]); },500); }); } let getList = async ()=>{ let result = await Promise.all([count(),list()]); return result; } console.time('begin'); getList().then(result => { console.timeEnd('begin'); //begin: 505.557ms console.log(result); //[ 100, [ 1, 2, 3 ] ] }).catch(err => { console.timeEnd('begin'); console.log(err); });
我們將count()和list()使用Promise.all()“同時(shí)”執(zhí)行,這里count()和list()可以看作是“并行”執(zhí)行的,所耗時(shí)間將是兩個(gè)異步操作中耗時(shí)最長(zhǎng)的耗時(shí)。
?? ??? ? ?? ??? ??? ??? ?????. ??? ?? ???? ???? ?? ???.
【?? ??: javascript ??? ????】
? ??? es6 ?? es7? ???? ?????? ?? ?????. ??? ??? PHP ??? ????? ?? ?? ??? ?????!

? AI ??

Undress AI Tool
??? ???? ??

Undresser.AI Undress
???? ?? ??? ??? ?? AI ?? ?

AI Clothes Remover
???? ?? ???? ??? AI ?????.

Clothoff.io
AI ? ???

Video Face Swap
??? ??? AI ?? ?? ??? ???? ?? ???? ??? ?? ????!

?? ??

??? ??

???++7.3.1
???? ?? ?? ?? ???

SublimeText3 ??? ??
??? ??, ???? ?? ????.

???? 13.0.1 ???
??? PHP ?? ?? ??

???? CS6
??? ? ?? ??

SublimeText3 Mac ??
? ??? ?? ?? ?????(SublimeText3)

ES6??? ?? ??? reverse() ???? ???? ?? ??? ??? ? ????. ? ???? ??? ?? ??? ??? ???? ??? ??? ?? ???? ? ?? ??? ???? ???? ? ?????. .???()". reverse() ???? ?? ??? ?????. ???? ???? ?? ??? "..."? ?? ???? ?? ??? "[...array].reverse()???. ".

???? es7???. async ? wait? ES7? ?? ??? ???? ??? ??? ?? ??????. async/await? ?? ?? ? ??? ??? ?? ?? ????? ? ? ???, ? ??? ??? js ??? ??? ?????. ???? ? ? ??? async? "???"? ?????. async? async? wait ??? ??? ??? ??? ???? ? ????, wait? ??? ???? ??? ? ????.

???? ???? ??. JS? ??? ???? ES6?? ??? ??? API? ?? ???????. ??? ?? ????? ES6? ??? ??? ? ???? ???? ES6 ??? ES5 ??? ???? ???. WeChat ? ??? ????? ???? ES6 ?? ??? ? ??? ???? ? ???? ES5 ??? ???? ? ????? babel? ?????. ?? ?? ???? ??????? ?? ?? ???? ?? ???? ?? ??? ??? ? ????. "ES6?? ES5?" ??.

??: 1. "newA=new Set(a);newB=new Set(b);" ??? ???? ? ??? ?? ?? ???? ?????. 2. has() ? filter()? ???? ??? ??? ????. , " new Set([...newA].filter(x =>!newB.has(x)))" ??? ???? ??? ?? ??? ?? ???? ???? ?????. 3. ??? ?????. from ??? ?? ???? ????? ?? "Array.from(collection)"? ?????.

es5??? for ?? indexOf() ??? ???? ?? ?? ??? ??? ? ????. ?? "for(i=0;i<array length;i++){a=newArr.indexOf(arr[i]);if( a== -1){...}}". es6??? ???? ??? Array.from() ? Set? ???? ??? ??? ? ????. ?? ??? Set ??? ???? ??? ??? ?? ???? ??? ?? Array.from() ??? ???? ???? ???. Set ??? ?? ??? ?????.

es6?? ?? ???? ??? ?? ??? ??? let ? const ??? ???? ?? ?????. ?? ?? ??? let/const ??? ???? ??? ???? ??? ?? ??? ??? ? ??? ??? ???? ??? ??? "?? ?"? ????. ?? ????? "?? ?? ?"??? ???. ES6??? ?? ???? let ? const ??? ?? ??? ???? ??? ???? ????. ?? ?? ??? ??? ??? ??? ???? ?? ??? ???? ??? ?? ??? ???? ?? ???? ?? ????.

ES6??? ?? ??? ?? ??? ???? ??? ?? ?? ?? ??? ? ????. ?, ??? ?? ?? ???? ? ? ??? ??? ?? ?? ??? ? ????. "array.length" ?? ?????. ?? ??? ?? ?, ? ?? ?? ?????.

ES6 ????? ?? ?? ??? ?????. ?? ????? ?? ??? ?? ??? ?? ???? ?????? ???????. Node.js? ??? ??? ?? ??? ??? ??, ?? ?? ??? ?? ???? ??? ????? ?? ???? ??? ???? ????. ??? ??? ???? ? ?? ??? ?? ????. ????, ? ?? ??? ?? ???? ???? ??? ?? ?????.
