Reputation: 94369
As far as I know, async/await
is just syntactic sugar over promise.then
. Consider this code snippet:
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
makes the code very linear, efficient and easy to understand. One thing to keep in mind is that range
does not have to have an actual end for this to work.
The problem now is how this can be rewritten using pre-ES7 era's promise.then
. Here's a possible implementation of the same loop:
function doStuff(){
return Array.from(range(10)).reduce((acc, ele) => {
return acc
.then(() => console.log(ele))
.then(() => sleep(1000))
}, Promise.resolve());
}
Ignoring the fact that the code isn't quite elegant, the use of Array.from(range(10))
range(10)
will end some point in the future.Doesn't look like a good conversion.
We can also completely reinvent the wheel by using yield
as await
, but that would make the syntax non ES5-compliant. The goal here is to:
sleep
functionsleep
promise while allowing the iterator to not have an enddoStuff
can be chained:
doStuff().finally(cleanUp); // clean up if something failed
(Optional) Code should not be overly complex
Any idea?
Upvotes: 4
Views: 246
Reputation: 114004
I've always said that if you need an asynchronous design pattern first look at the async library. In this case, since you're using promises, take a look at the promisified async-q library. The translation is straight forward:
var n = 0;
async.whilst(() => n < 10, () => {
n++;
console.log(n);
return sleep(1000);
})
Upvotes: 1
Reputation: 39320
I think the following may do the trick, your example doesn't show what to do with resolve value and how it relates to the iterator values so I made a change to how sleep is called.
Some promise polyfils may run out of stack space with high promise chains so you should check your polyfil (if its implementation returns and continues with a setTimeout the stack should clear but some polyfils may not implement it this way).
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)
);
Upvotes: 1