在 foreach 循环中使用回调函数
function with callback in foreach loop
我正在尝试在 forEach
循环中使用带回调的函数。
我需要等待执行完成才能继续下一步。
这是我的代码:
const arr = '6,7,7,8,8,5,3,5,1'
const id = arr.split(',');
const length = id.length;
id.forEach( (x, index) => {
(function FnWithCallback () {
setTimeout(() => { console.log(x) }, 5000);
})();
});
console.log('done');
我想到了一个技巧:
const arr = '6,7,7,8,8,5,3,5,1'
const id = arr.split(',');
const length = id.length;
const fn = () => {
return new Promise (resolve => {
id.forEach( (id, index) => {
setTimeout(() => {console.log(id)}, 3000);
if(index === (length - 1))
resolve();
})
})
}
fn().then(()=> {
console.log('done');
})
但是黑客似乎被破解了。
我能有一个真正的解决方案吗?
NPM 包会很有帮助。
注意:我看过 async.js。我不确定这是否是我想要的,因为我正在努力避免回调地狱。
解决方法是promisify回调函数然后使用Array.prototype.map()
coupled with Promise.all()
:
const arr = '6,7,7,8,8,5,3,5,1'
function FnWithCallback (id, cb) {
setTimeout(cb, 1000, id)
}
const promisified = id => new Promise(resolve => {
FnWithCallback(id, resolve)
})
const promises = arr.split(',').map(promisified)
Promise.all(promises).then(id => {
console.log(id)
console.log('Done')
})
如果你的回调 API 遵循 (error, result) => ...
的 Node.js 约定,那么你应该使用 util.promisify()
来 promisify 函数,或者查看文档以查看是否省略回调参数将导致调用 return 承诺,因为许多包现在提供基于承诺的 API 开箱即用。
如果您想确保异步操作不是 运行 并行而是一个接一个地进行,请继续阅读。如果您想按顺序获得结果但不关心它们是否 运行 并行,请参阅 .
您可以使用 async
函数在 for
循环中 await
承诺,因为承诺的计时器非常有用:
const timer = ms => new Promise(res => setTimeout(res, ms));
(async function() {
for(const id of ["6", "7", "7" /*...*/]) {
await timer(5000);
console.log(id);
}
console.log("done");
})();
这也可以使用回调链来实现,但是我不确定这是否可以理解/有用(只是想表明回调不一定来自地狱):
["6", "7", "7" /*..*/].reduceRight(
(next, id) => () => setTimeout(() => {
console.log(id);
next();
}, 5000),
() => console.log("done")
)();
您可以使用 Array.prototype.reduce()
链式承诺,从最初已解决的承诺开始。你必须将你的回调变成一个承诺,以便你可以链接它们:
const arr = '6,7,7,8,8,5,3,5,1'
const ids = arr.split(',');
const length = ids.length;
const timeout = (fn, ms) => new Promise(res => {
setTimeout(() => { fn(); res(); }, ms);
});
ids.reduce((previousPromise, id) => {
return previousPromise.then(() => {
return timeout(() => console.log(id), 200);
});
}, Promise.resolve());
console.log('done');
或使用async/await:
const arr = '6,7,7,8,8,5,3,5,1'
const ids = arr.split(',');
const length = ids.length;
const timeout = (fn, ms) => new Promise(res => {
setTimeout(() => { fn(); res(); }, ms);
});
ids.reduce(async (previousPromise, id) => {
await previousPromise;
return timeout(() => console.log(id), 200);
}, Promise.resolve());
console.log('done');
您可以尝试这种方法,其中 promisefy
将接收任何类型的值作为之后要解析的参数。
const IDs = '6,7,7,8,8,5,3,5,1'.split(',');
// simulates an async response after 1s
const promisefy = (value) => new Promise((resolve) => {
setTimeout(() => {
resolve(value);
}, 1000);
});
// stores all async responses
const responses = IDs.map((id, index) => {
return promisefy(id);
});
// executes sequentially all responses
responses.forEach((resp, index) => {
resp.then((value) => console.log(`id: ${value}, index: ${index}`));
});
// stores all async responses
const responses2 = IDs.map((id) => promisefy(id));
// executes sequentially all responses
responses2
.reduce((_, resp, index) => {
return resp.then((value) => console.log(`id: ${value}, index: ${index}`));
}, null)
.then(() => console.log('done'));
我正在尝试在 forEach
循环中使用带回调的函数。
我需要等待执行完成才能继续下一步。
这是我的代码:
const arr = '6,7,7,8,8,5,3,5,1'
const id = arr.split(',');
const length = id.length;
id.forEach( (x, index) => {
(function FnWithCallback () {
setTimeout(() => { console.log(x) }, 5000);
})();
});
console.log('done');
我想到了一个技巧:
const arr = '6,7,7,8,8,5,3,5,1'
const id = arr.split(',');
const length = id.length;
const fn = () => {
return new Promise (resolve => {
id.forEach( (id, index) => {
setTimeout(() => {console.log(id)}, 3000);
if(index === (length - 1))
resolve();
})
})
}
fn().then(()=> {
console.log('done');
})
但是黑客似乎被破解了。
我能有一个真正的解决方案吗? NPM 包会很有帮助。
注意:我看过 async.js。我不确定这是否是我想要的,因为我正在努力避免回调地狱。
解决方法是promisify回调函数然后使用Array.prototype.map()
coupled with Promise.all()
:
const arr = '6,7,7,8,8,5,3,5,1'
function FnWithCallback (id, cb) {
setTimeout(cb, 1000, id)
}
const promisified = id => new Promise(resolve => {
FnWithCallback(id, resolve)
})
const promises = arr.split(',').map(promisified)
Promise.all(promises).then(id => {
console.log(id)
console.log('Done')
})
如果你的回调 API 遵循 (error, result) => ...
的 Node.js 约定,那么你应该使用 util.promisify()
来 promisify 函数,或者查看文档以查看是否省略回调参数将导致调用 return 承诺,因为许多包现在提供基于承诺的 API 开箱即用。
如果您想确保异步操作不是 运行 并行而是一个接一个地进行,请继续阅读。如果您想按顺序获得结果但不关心它们是否 运行 并行,请参阅
您可以使用 async
函数在 for
循环中 await
承诺,因为承诺的计时器非常有用:
const timer = ms => new Promise(res => setTimeout(res, ms));
(async function() {
for(const id of ["6", "7", "7" /*...*/]) {
await timer(5000);
console.log(id);
}
console.log("done");
})();
这也可以使用回调链来实现,但是我不确定这是否可以理解/有用(只是想表明回调不一定来自地狱):
["6", "7", "7" /*..*/].reduceRight(
(next, id) => () => setTimeout(() => {
console.log(id);
next();
}, 5000),
() => console.log("done")
)();
您可以使用 Array.prototype.reduce()
链式承诺,从最初已解决的承诺开始。你必须将你的回调变成一个承诺,以便你可以链接它们:
const arr = '6,7,7,8,8,5,3,5,1'
const ids = arr.split(',');
const length = ids.length;
const timeout = (fn, ms) => new Promise(res => {
setTimeout(() => { fn(); res(); }, ms);
});
ids.reduce((previousPromise, id) => {
return previousPromise.then(() => {
return timeout(() => console.log(id), 200);
});
}, Promise.resolve());
console.log('done');
或使用async/await:
const arr = '6,7,7,8,8,5,3,5,1'
const ids = arr.split(',');
const length = ids.length;
const timeout = (fn, ms) => new Promise(res => {
setTimeout(() => { fn(); res(); }, ms);
});
ids.reduce(async (previousPromise, id) => {
await previousPromise;
return timeout(() => console.log(id), 200);
}, Promise.resolve());
console.log('done');
您可以尝试这种方法,其中 promisefy
将接收任何类型的值作为之后要解析的参数。
const IDs = '6,7,7,8,8,5,3,5,1'.split(',');
// simulates an async response after 1s
const promisefy = (value) => new Promise((resolve) => {
setTimeout(() => {
resolve(value);
}, 1000);
});
// stores all async responses
const responses = IDs.map((id, index) => {
return promisefy(id);
});
// executes sequentially all responses
responses.forEach((resp, index) => {
resp.then((value) => console.log(`id: ${value}, index: ${index}`));
});
// stores all async responses
const responses2 = IDs.map((id) => promisefy(id));
// executes sequentially all responses
responses2
.reduce((_, resp, index) => {
return resp.then((value) => console.log(`id: ${value}, index: ${index}`));
}, null)
.then(() => console.log('done'));