這篇文章主要介紹“async是es7的嗎”,在日常操作中,相信很多人在async是es7的嗎問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”async是es7的嗎”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
創(chuàng)新互聯(lián)建站作為成都網(wǎng)站建設(shè)公司,專注網(wǎng)站建設(shè)公司、網(wǎng)站設(shè)計(jì),有關(guān)企業(yè)網(wǎng)站設(shè)計(jì)方案、改版、費(fèi)用等問題,行業(yè)涉及成都雨棚定制等多個(gè)領(lǐng)域,已為上千家企業(yè)服務(wù),得到了客戶的尊重與認(rèn)可。
async是es7的。async和await是ES7中新增內(nèi)容,是對于異步操作的解決方案;async/await可以說是co模塊和生成器函數(shù)的語法糖,用更加清晰的語義解決js異步代碼。async顧名思義是“異步”的意思,async用于聲明一個(gè)函數(shù)是異步的;async和await有一個(gè)嚴(yán)格規(guī)定,兩者都離不開對方,且await只能寫在async函數(shù)中。
ES7(ES2017)中提出的前端異步特性:async、await。
async和await是ES7中新增內(nèi)容,對于異步操作的解決方案,async/await可以說是co模塊和生成器函數(shù)的語法糖。用更加清晰的語義解決js異步代碼。
async顧名思義是“異步”的意思,async用于聲明一個(gè)函數(shù)是異步的。而await從字面意思上是“等待”的意思,就是用于等待異步完成。
async和await它們兩有一個(gè)嚴(yán)格規(guī)定,兩者都離不開對方,但是,await只能寫在async函數(shù)中。
熟悉co模塊的同學(xué)應(yīng)該都知道,co模塊是TJ大神寫的一個(gè)使用生成器函數(shù)來解決異步流程的模塊,可以看做是生成器函數(shù)的執(zhí)行器。而async/await則是對co模塊的升級,內(nèi)置生成器函數(shù)的執(zhí)行器,不再依賴co模塊。同時(shí),async返回的是Promise。
從上面來看,不管是co模塊還是async/await,都是將Promise作為最基礎(chǔ)的單元,對Promise不很了解的同學(xué)可以先深入了解一下Promise。
下面我們使用一個(gè)簡單的例子,來對比一下三種方式的異同,以及取舍。
我們采用MongoDB的nodejs驅(qū)動,查詢mongodb數(shù)據(jù)庫作為例子,原因是mongodb的js驅(qū)動已經(jīng)默認(rèn)實(shí)現(xiàn)了返回Promise,而不用我們單獨(dú)去包裝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()方法可以返回另一個(gè)Promise,也可以返回一個(gè)同步的值,如果返回的是一個(gè)同步值,將會被包裝成一個(gè)Promise。上面的例子中,db.collection()將返回一個(gè)同步的值,即集合對象,但是被包裝成Promise,將會透傳到下一個(gè)then()方法。上面一個(gè)例子,是使用的Promise鏈。先連接數(shù)據(jù)庫MongoClient.connect()返回一個(gè)Promise,然后在then()方法里獲得數(shù)據(jù)庫對象db,然后再獲取到coll對象再返回。在下一個(gè)then()方法獲得coll對象,然后進(jìn)行查詢,查詢結(jié)果返回,逐層調(diào)用then()方法,形成一個(gè)Promise鏈。在這個(gè)Promise鏈上,如果任何一個(gè)環(huán)節(jié)出現(xiàn)異常,都會被最后的catch()捕捉到??梢哉f,這個(gè)使用Promise鏈寫的代碼,比層層調(diào)用回調(diào)函數(shù)更優(yōu)雅,流程也更明確。先獲得數(shù)據(jù)庫對象,再獲得集合對象,最后查詢數(shù)據(jù)。但是這里有個(gè)不怎么“優(yōu)雅”的問題,在于,每一個(gè)then()方法獲取的對象,都是上一個(gè)then()方法返回的數(shù)據(jù)。而不能跨層訪問。什么意思,就是說在第三個(gè)then(blogs => {})中我們只能獲取到查詢的結(jié)果blogs,而不能使用上面的db對象和coll對象。這個(gè)時(shí)候,如果要打印出blogs列表后,要關(guān)閉數(shù)據(jù)庫db.close()怎么辦?這個(gè)時(shí)候,可以兩種解決方法:
第一種是,使用then()嵌套。我們將Promise鏈打斷,使之嵌套,猶如使用回調(diào)函數(shù)的嵌套一般:
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);
})
這里我們將兩個(gè)Promise嵌套,這樣在最后一個(gè)查詢操作里面,就可以調(diào)用外面的db對象了。但是這中方式,并不推薦。原因很簡單,我們從一種回調(diào)函數(shù)地獄走向了另一種Promise回調(diào)地獄。
而且,我們要對每個(gè)Promise的異常進(jìn)行捕捉,因?yàn)镻romise沒有形成鏈。
還有一種方式, 是在每個(gè)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);
});
我們在每個(gè)then()方法的返回中,都將db及其每次的其他結(jié)果組成一個(gè)對象返回。請注意,如果每次的結(jié)果都是一個(gè)同步的值還好說,但是如果是一個(gè)Promise值,每一個(gè)Promise都需要多做一層解析。
例如上面的一個(gè)例子,第二個(gè)then()方法返回的{db:result.db,blogs:result.coll.find().toArray()}
對象中,blogs
是一個(gè)Promise,在下一個(gè)then()方法中,我們無法直接引用博客列表數(shù)組值,因此需要先調(diào)用then()方法解析一層,然后將兩個(gè)同步值db和blogs返回。注意,這里涉及到了Promise的嵌套,不過一個(gè)Promise只嵌套一層then()。
這種方式,也是很蛋疼的一個(gè)方式,因?yàn)槿绻龅絫hen()方法中返回的不是同步的值,而是Promise的話,我們需要多做很多工作。而且,每次都透傳一個(gè)“多余”的db對象,在邏輯上也有點(diǎn)冗余。
但除此之外,對于Promise鏈的使用,如果遇到上面的問題,好像也沒其他更好的方法解決了。我們只能根據(jù)場景去選擇一種“最優(yōu)”的方案,如果要使用Promise鏈的話。
鑒于Promise上面蛋疼的問題,TJ大神將ES6中的生成器函數(shù),用co模塊包裝了一下,以更優(yōu)雅的方式來解決上面的問題。
如果使用co模塊搭配生成器函數(shù),那么上面的例子可以改寫如下:
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)鍵字來“同步”獲取每個(gè)異步操作的值。
上面代碼在代碼形式上,比上面使用Promise鏈要優(yōu)雅,我們消滅了回調(diào)函數(shù),代碼看起來都是同步的。除了使用co和yield有點(diǎn)怪之外。
使用co模塊,我們要將所有的操作包裝成一個(gè)生成器函數(shù),然后使用co()去調(diào)用這個(gè)生成器函數(shù)??瓷先ヒ策€可以接受,但是ES的進(jìn)化是不滿足于此的,于是async/await被提到了ES7的提案。
我們先看一下使用async/await改寫上面的代碼:
(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);
});
我們對比代碼可以看出,async/await和co兩種方式代碼極為相似。co換成了async,yield換成了await。同時(shí)生成器函數(shù)變成了普通函數(shù)。這種方式在語義上更加清晰明了,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ù),最后返回得到的博客列表最終會被包裝成一個(gè)Promise返回,如上,我們直接調(diào)用getBlogs().then()方法可獲取async函數(shù)返回值。
好了,上面我們簡單對比了一下三種解決異步方案,下面我們來深入了解一下async/await。
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()方法獲取返回值。對于一個(gè)同步的值,可以使用await,也可以不使用await。效果效果是一樣的。具體用不用,看情況。
比如上面使用mongodb查詢博客那個(gè)例子,let coll = db.collection('blogs');
,這里我們就沒有用await,因?yàn)檫@是一個(gè)同步的值。當(dāng)然,也可以使用await,這樣會顯得代碼統(tǒng)一。雖然效果是一樣的。
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鏈的對比:
我們的async函數(shù)中可以包含多個(gè)異步操作,其異常和Promise鏈有相同之處,如果有一個(gè)Promise被reject()那么后面的將不會再進(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é)果來看,count()拋出異常后,直接由catch()捕捉到了,list()并沒有繼續(xù)執(zhí)行。
使用async后,我們上面的例子都是串行的。比如上個(gè)list()和count()的例子,我們可以將這個(gè)例子用作分頁查詢數(shù)據(jù)的場景。先查詢出數(shù)據(jù)庫中總共有多少條記錄,然后再根據(jù)分頁條件查詢分頁數(shù)據(jù),最后返回分頁數(shù)據(jù)以及分頁信息。
我們上面的例子count()和list()有個(gè)“先后順序”,即我們先查的總數(shù),然后又查的列表。其實(shí),這兩個(gè)操作并無先后關(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í)最長的耗時(shí)。最后得到的結(jié)果是兩個(gè)操作的結(jié)果組成的數(shù)組。我們只需要按照順序取出數(shù)組中的值即可。
到此,關(guān)于“async是es7的嗎”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
網(wǎng)頁名稱:async是es7的嗎
標(biāo)題路徑:http://aaarwkj.com/article6/igcpog.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司、Google、品牌網(wǎng)站建設(shè)、小程序開發(fā)、全網(wǎng)營銷推廣、移動網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)