node.js:如何使用序列和承诺对两个 aync 循环进行建模



我在node.js中有两个函数,我们称它们为func_A和func_B,它们都需要在一个循环中调用,但这需要一个接一个地发生。

首先,func_a需要在循环中调用 num1 次。

for (i=0; i<num1; i++)
{
func_a(i, function(err,cb1))
}

当上述操作完成后,func_b需要在循环中调用 num2 次

for (j=0; j<num2; j++)
{
func_b(j, function(err,cb2))
}

当上述所有 aync 函数调用完成并返回时,我需要对两个 cb 结果做其他事情。 我可以使用地狱般的回调金字塔来执行上述操作,并使用计数器来跟踪回调完成情况。 但我想使用序列并承诺来简化我的代码。对于上述内容,我该如何做到这一点? 我不太清楚如何使用循环调用的函数来完成它。

在制作了func_a()func_b()的 promisized 版本后,您可以使用Promise.all()并在async functionawait聚合结果,而无需使用计数器:

const promisify = fn => function () {
return new Promise((resolve, reject) => {
// forward context and arguments of call
fn.call(this, ...arguments, (error, result) => {
if (error) {
reject(error)
} else {
resolve(result)
}
})
})
}
const func_a_promisified = promisify(func_a)
const func_b_promisified = promisify(func_b)
async function loop_a_b (num1, num2) {
// await pauses execution until all asynchronous callbacks have been invoked
const results_a = await Promise.all(
Array.from(Array(num1).keys()).map(i => func_a_promisified(i))
)
const results_b = await Promise.all(
Array.from(Array(num2).keys()).map(j => func_b_promisified(j))
)
return {
a: results_a,
b: results_b
}
}
// usage
loop_a_b(3, 4).then(({ a, b }) => {
// iff no errors encountered
// a contains 3 results in order of i [0..2]
// b contains 4 results in order of j [0..3]
}).catch(error => {
// error is first encountered error in chronological order of callback results
})

为了简化Array.from(...).map(...)混乱,您可以编写一个帮助程序生成器函数来并发调用异步函数:

function * loop_fn_n (fn, n) {
for (let i = 0; i < n; i++) {
yield fn(n)
}
}

然后将loop_a_b更改为:

async function loop_a_b (num1, num2) {
// await pauses execution until all asynchronous callbacks have been invoked
const results_a = await Promise.all(
loop_fn_n(func_a_promisified, num1)
)
const results_b = await Promise.all(
loop_fn_n(func_b_promisified, num2)
)
return {
a: results_a,
b: results_b
}
}

正如@OleksiiTrekhleb指出的那样,我在这里实现的promisify函数也可以在 Node.js 核心模块util中找到。

您可以使用 Promise 并将您的异步函数包装在其中。 我没有测试它,但逻辑应该有效

let _func_a = (i) => {
return new Promise(function (resolve, reject) {
func_a(i, function (err, res) {
if (err) {
return reject(err);
}
return resolve(res);
})
})
}   
let _func_b = (j) => {
return new Promise(function (resolve, reject) {
func_b(j, function (err, res) {
if (err) {
return reject(err);
}
return resolve(res);
})
})
}   
(async function loop() {
try {
for (i=0; i<num1; i++){
let a = await _func_a(i)
}
for (j=0; j<num2; j++){
let b = await _func_b(j)
}
console.log("here you're sure both for loops are done")
} catch(err) {
console.error("some error has occurred")
}
})();

你试过util.promisify(original(吗?

您提到的代码可能会转换为以下内容:

// Dependencies.
const util = require('util');
// Promisify your functions.
const func_a_as_promise = util.promisify(func_a);
const func_b_as_promise = util.promisify(func_b);
// Now we may create 'async' function with 'await's.
async function doSomething() {
// Some data containers if you need any (?).
const someDataA = [];
const someDataB = [];
// First async loop that looks like sync one.
for (i=0; i < num1; i++){
someDataA[i] = await func_a_as_promise(i);
}
// Second async loop that looks as sync one.
for (j=0; j < num2; j++) {
someDataB[j] = await func_b_as_promise(j);
}
// Do something with someDataA and someDataB here...
// You'll get here after all async loops above are finished.
}

最新更新