[英]Converting await in infinite for loop into raw promise.then
據我所知, async/await
只是對promise.then
語法糖。 請考慮以下代碼段:
function sleep(n){
return new Promise(res => setTimeout(res, n));
}
function* range(n){
var i = 0;
while(i < n) yield i++;
}
async function doStuff(){
for(let n of range(10)){
console.log(n); // print the number
await sleep(1000); // wait for 1 second
}
}
async/await
使代碼非常線性,高效且易於理解。 要記住的一件事是, range
不必具有實際結束。
現在的問題是如何使用pre-ES7時代的promise.then
來重寫它promise.then
。 這是同一循環的可能實現:
function doStuff(){
return Array.from(range(10)).reduce((acc, ele) => {
return acc
.then(() => console.log(ele))
.then(() => sleep(1000))
}, Promise.resolve());
}
忽略代碼不太優雅的事實,使用Array.from(range(10))
range(10)
將在未來結束某一點。 看起來不是很好的轉換。
我們也可以通過使用yield
作為await
來完全重新發明輪子,但這會使語法不符合ES5。 這里的目標是:
sleep
功能 sleep
承諾,同時允許迭代器沒有結束 doStuff
可以鏈接:
doStuff().finally(cleanUp); // clean up if something failed
(可選)代碼不應過於復雜
任何的想法?
我認為以下可能會有這個技巧,你的例子沒有說明如何處理解析值以及它與迭代器值的關系,所以我改變了如何調用sleep。
一些承諾polyfils可能會耗盡具有高promise鏈的堆棧空間,所以你應該檢查你的polyfil(如果它的實現返回並繼續使用setTimeout,堆棧應該清除,但是一些polyfils可能不會以這種方式實現它)。
function sleep(n){ return new Promise(res => setTimeout(_=>res(n/100), n)); } function* range(n){ var i = 0; while(i < n) yield i++; } function doStuff(){ const processValue = resolve => { console.log("resolved with:",resolve); // if(resolve===3){throw "nope";} return sleep(resolve*100); }, rec = (p,iter) => { const result = iter.next(); if (result.done){ return p; } p = p.then(_=>processValue(result.value)) return p.then( resolve=>{ return rec(p,iter) } ); }, iter = range(10), firstResult = iter.next(); if(firstResult.done){ return processValue(firstResult.value); } return rec(processValue(firstResult.value),iter); } doStuff() .then( x=>console.log("done:",x) ,reject=>console.warn("fail:",reject) );
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.