async/await剖析
async/await剖析
JavaScript
是單線程的,為了避免同步阻塞可能會帶來的一些負面影響,引入了異步非阻塞機制,而對於異步執行的解決方案從最早的回調函數,到ES6
的Promise
對象以及Generator
函數,每次都有所改進,但是卻又美中不足,他們都有額外的複雜性,都需要理解抽象的底層運行機制,直到在ES7
中引入了async/await
,他可以簡化使用多個Promise
時的同步行為,在編程的時候甚至都不需要關心這個操作是否為異步操作。
分析
首先使用async/await
執行一組異步操作,並不需要回調嵌套也不需要寫多個then
方法,在使用上甚至覺得這本身就是一個同步操作,當然在正式使用上應該將await
語句放置於 try...catch
代碼塊中,因為await
命令後面的Promise
對象,運行結果可能是rejected
。
function promise(){
return new Promise((resolve, reject) => {
var rand = Math.random() * 2;
setTimeout(() => resolve(rand), 1000);
});
}
async function asyncFunct(){
var r1 = await promise();
console.log(1, r1);
var r2 = await promise();
console.log(2, r2);
var r3 = await promise();
console.log(3, r3);
}
asyncFunct();
async/await
實際上是Generator
函數的語法糖,如Promises
類似於結構化回調,async/await
在實現上結合了Generator
函數與Promise
函數,下面使用Generator
函數加Thunk
函數的形式實現一個與上邊相同的例子,可以看到只是將async
替換成了*
放置在函數右端,並將await
替換成了yield
,所以說async/await
實際上是Generator
函數的語法糖,此處唯一不同的地方在於實現了一個流程的自動管理函數run
,而async/await
內置了執行器,關於這個例子的實現下邊會詳述。對比來看,async
和await
,比起*
和yield
,語義更清楚,async
表示函數里有異步操作,await
表示緊跟在後面的表達式需要等待結果。
function thunkFunct(index){
return function f(funct){
var rand = Math.random() * 2;
setTimeout(() => funct(rand), 1000)
}
}
function* generator(){
var r1 = yield thunkFunct();
console.log(1, r1);
var r2 = yield thunkFunct();
console.log(2, r2);
var r3 = yield thunkFunct();
console.log(3, r3);
}
function run(generator){
var g = generator();
var next = function(data){
var res = g.next(data);
if(res.done) return ;
// console.log(res.value);
res.value(next);
}
next();
}
run(generator);
實現
async
函數內置了執行器,能夠實現函數執行的自動流程管理,通過Generator yield Thunk
、Generator yield Promise
實現一個自動流程管理,只需要編寫Generator
函數以及Thunk
函數或者Promise
對象並傳入自執行函數,就可以實現類似於async/await
的效果。
Generator yield Thunk
自動流程管理run
函數,首先需要知道在調用next()
方法時,如果傳入了參數,那麼這個參數會傳給上一條執行的yield
語句左邊的變量,在這個函數中,第一次執行next
時並未傳遞參數,而且在第一個yield
上邊也並不存在接收變量的語句,無需傳遞參數,接下來就是判斷是否執行完這個生成器函數,在這裏並沒有執行完,那麼將自定義的next
函數傳入res.value
中,這裏需要注意res.value
是一個函數,可以在下邊的例子中將註釋的那一行執行,然後就可以看到這個值是f(funct){...}
,此時我們將自定義的next
函數傳遞后,就將next
的執行權限交予了f
這個函數,在這個函數執行完異步任務后,會執行回調函數,在這個回調函數中會觸發生成器的下一個next
方法,並且這個next
方法是傳遞了參數的,上文提到傳入參數後會將其傳遞給上一條執行的yield
語句左邊的變量,那麼在這一次執行中會將這個參數值傳遞給r1
,然後在繼續執行next
,不斷往複,直到生成器函數結束運行,這樣就實現了流程的自動管理。
function thunkFunct(index){
return function f(funct){
var rand = Math.random() * 2;
setTimeout(() => funct(rand), 1000)
}
}
function* generator(){
var r1 = yield thunkFunct();
console.log(1, r1);
var r2 = yield thunkFunct();
console.log(2, r2);
var r3 = yield thunkFunct();
console.log(3, r3);
}
function run(generator){
var g = generator();
var next = function(data){
var res = g.next(data);
if(res.done) return ;
// console.log(res.value);
res.value(next);
}
next();
}
run(generator);
Generator yield Promise
相對於使用Thunk
函數來做流程自動管理,使用Promise
來實現相對更加簡單,Promise
實例能夠知道上一次回調什麼時候執行,通過then
方法啟動下一個yield
,不斷繼續執行,這樣就實現了流程的自動管理。
function promise(){
return new Promise((resolve,reject) => {
var rand = Math.random() * 2;
setTimeout( () => resolve(rand), 1000);
})
}
function* generator(){
var r1 = yield promise();
console.log(1, r1);
var r2 = yield promise();
console.log(2, r2);
var r3 = yield promise();
console.log(3, r3);
}
function run(generator){
var g = generator();
var next = function(data){
var res = g.next(data);
if(res.done) return ;
res.value.then(data => next(data));
}
next();
}
run(generator);
// 比較完整的流程自動管理函數
function promise(){
return new Promise((resolve,reject) => {
var rand = Math.random() * 2;
setTimeout( () => resolve(rand), 1000);
})
}
function* generator(){
var r1 = yield promise();
console.log(1, r1);
var r2 = yield promise();
console.log(2, r2);
var r3 = yield promise();
console.log(3, r3);
}
function run(generator){
return new Promise((resolve, reject) => {
var g = generator();
var next = function(data){
var res = null;
try{
res = g.next(data);
}catch(e){
return reject(e);
}
if(!res) return reject(null);
if(res.done) return resolve(res.value);
Promise.resolve(res.value).then(data => {
next(data);
},(e) => {
throw new Error(e);
});
}
next();
})
}
run(generator).then( () => {
console.log("Finish");
});
每日一題
https://github.com/WindrunnerMax/EveryDay
參考
https://segmentfault.com/a/1190000007535316
http://www.ruanyifeng.com/blog/2015/05/co.html
http://www.ruanyifeng.com/blog/2015/05/async.html
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※別再煩惱如何寫文案,掌握八大原則!
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※超省錢租車方案
※教你寫出一流的銷售文案?
※網頁設計最專業,超強功能平台可客製化