上一篇《[讓 Generator 自啟動][generator]》介紹了通過起動器讓 Generator 跑起來,而本篇採用 async 實現更優雅的非同步編程。 <! more 從例子開始 借用上一篇例子中的例子說起。 然後,我們需要寫一個啟動器來啟動這個函數。 而採用 async 寫,代碼則是: ...
上一篇《讓 Generator 自啟動》介紹了通過起動器讓 Generator 跑起來,而本篇採用 async 實現更優雅的非同步編程。
從例子開始
借用上一篇例子中的例子說起。
function* gen() {
var r1 = yield $.get('url1');
var r2 = yield $.get('url2');
var r3 = yield $.get('url3');
console.log(r1, r2, r3);
}
然後,我們需要寫一個啟動器來啟動這個函數。
而採用 async 寫,代碼則是:
async function gen() {
var r1 = await $.get('url1');
var r2 = await $.get('url2');
var r3 = await $.get('url3');
console.log([r1, r2, r3].join('\n'));
}
gen(); // 直接運行即可
直接運行了,無須寫生成器來運行了,而代碼僅僅是 *
改為 async
, yield
改為 await
而已。
所以本質上講:async 就是 Generator 的語法糖。
多任務處理
多任務處理有個坑,就是不能直接在 forEach
, map
之類的方法里處理,否則會報錯或者得到錯誤的結果。
function sleep(t) {
return new Promise(resolve => setTimeout( _ => { resolve(+new Date) }, t))
}
async function run() {
// 順序
let a = await sleep(100)
let b = await sleep(200)
// 併發1
let c = await Promise.all([sleep(100), sleep(200), sleep(300)])
// 併發2
let d = await Promise.all([100, 200, 300].map(t => sleep(t)))
// 併發3
let list = [sleep(100), sleep(200), sleep(300)]
let e = []
for (let fn of list) {
e.push(await fn)
}
console.log(
'',
'a:', a, '\n',
'b:', b, '\n',
'c:', c, '\n',
'd:', d, '\n',
'e:', e, '\n'
)
}
run()
// a: 1468317737179
// b: 1468317737384
// c: [ 1468317737485, 1468317737589, 1468317737688 ]
// d: [ 1468317737792, 1468317737890, 1468317737989 ]
// e: [ 1468317738094, 1468317738193, 1468317738293 ]
小結
async 沒多大的變動,歸根結底就是個語法糖,幫助我們運行生成器,而不需要我們自己寫起動器了。
不過效果確實非常好,讓非同步編程更加的同步
了。