I want to chain the promises returned by a generator function.
I am expecting this to print:
started...
result is: initial value
result is: waited for 10ms
result is: waited for 20ms
done
But it prints:
started...
result is: initial value
undefined
result is: waited for 10ms
done
What am I doing wrong?
const wait = async(ms) =>
await new Promise((resolve) =>
setTimeout((result = `waited for ${ms}ms`)=>resolve(result),ms))
const iterator = {
*[Symbol.iterator]() {
yield wait(10)
yield wait(20)
}
}
function chain(i) {
return [...i].reduce((acc,c) =>
acc.then((result) =>
(console.log(`result is: ${result}`), c)), Promise.resolve('initial value'))
}
chain(iterator).then(() => console.log('done'))
console.log('started...')
The things is that your console.log
was lagging by 1 element. So your iterations were like that:
then
, gets '20ms' a result but doesn't log it, instead logs 'done'You could see it in the next sample, that done part logs '20ms':
const wait = async(ms) =>
await new Promise((resolve) =>
setTimeout(resolve,ms, `waited for ${ms}ms`))
const iterator = {
*[Symbol.iterator]() {
yield wait(10)
yield wait(20)
}
}
function chain(i) {
return [...i].reduce((acc,c) =>
acc.then((result) => (console.log(`result is: ${result}`), c)), Promise.resolve('initial value'))
}
chain(iterator).then((val) => console.log('done', val)) // <~ 20ms logs here
console.log('started...')
But wait, would you like to really wait
sequentially for 10ms and then for 20ms, right? Because your current version isn't doing this. It just runs them in parallel, so probably you should do it in this way:
const wait = ms => new Promise((resolve) => setTimeout(resolve,ms, `waited for ${ms}ms`))
const iterator = {
*[Symbol.iterator]() {
yield wait(500)
yield wait(1000)
}
}
async function chain(i) {
console.log('init')
for (const promise of i) {
const result = await promise
console.log(`result is: ${result}`)
}
}
chain(iterator).then(() => console.log('done'))
console.log('started...')