NodeJS在返回之前从异步回调中构造数组
我在写一个返回值和数组数组。一些值是在回调中计算的。但我不知道如何使程序异步,因此我的所有结果都在数组中,并且在返回后不会添加。NodeJS在返回之前从异步回调中构造数组
let array = []
for (stuff : stuffs) {
if (condition) {
array.add(stuff)
} else {
api.compute(stuff, callback(resp) {
array.add(resp.stuff)
}
}
}
res.json({ "stuff": array })
在这个例子中,在异步调用完成之前,数组被写入响应。
我怎样才能使这项工作异步?
你必须使用的方法之一:
- 异步库
- Promise.all
- 协同程序/发电机
- 异步/等待
最酷劲十足,我认为,是async/await
。首先,我们修改的功能,所以它返回一个承诺:
const compute = function(stuff) {
return new Promise((resolve, reject) => {
api.compute(stuff, callback(resp){
resolve(resp.stuff)
});
});
};
然后,我们用异步处理程序修改您的路线:
app.get('/', async function(req, res, next) {
const array = [];
for (const stuff of stuffs) {
if (condition) {
array.add(stuff);
} else {
const stuff = await compute(stuff);
array.push(stuff);
}
}
res.json({ stuff: array });
});
注:您可能需要节点版本更新到最新版本。
UPDATE:
这些谁没有awared,怎么事件循环工作,执行这个片段,并与完成:
const sleep = async function(ms) {
console.log(`Sleeping ${ms}ms`);
return new Promise(resolve => setTimeout(resolve, ms));
};
async function job() {
console.log('start');
for (let t = 0; t < 10; t++) {
await sleep(100);
}
}
job();
console.log('oops did not expect that oO');
你会感到惊讶。
这里是不使用包装回调
创建的会递归处理所有东西的功能答案。
getArray(stuffs, callback, index = 0, array = []) {
// Did we treat all stuffs?
if (stuffs.length >= index) {
return callback(array);
}
// Treat one stuff
if (condition) {
array.add(stuffs[index]);
// Call next
return getArray(stuffs, callback, index + 1, array);
}
// Get a stuff asynchronously
return api.compute(stuffs[index], (resp) => {
array.add(resp.stuff);
// Call next
return getArray(stuffs, callback, index + 1, array);
});
}
如何称呼呢?
getArray(stuffs, (array) => {
// Here you have your array
// ...
});
编辑:更多的解释
我们想要做的改变您必须为一个循环,处理异步函数调用的循环是什么。
目的是要求一个getArray
调用你的stuffs
阵列的索引。
处理完一个索引后,该函数会再次调用自身来处理下一个索引,直到所有对象都得到处理。
-> Treat index 0 -> Treat index 1 -> Treat index 2 -> Return all result
我们正在使用参数传递过程中的信息。 Index
知道我们必须对待哪个阵列部分,并且保留我们计算的一小部分。
编辑:提高到100%异步soluce
我们在这里做了它的初始for循环的一个简单的换位成异步代码。它可以通过完全异步进行改进,这使它更好,但稍微困难一些。
例如:
// Where we store the results
const array = [];
const calculationIsDone = (array) => {
// Here our calculation is done
// ---
};
// Function that's gonna aggregate the results coming asynchronously
// When we did gather all results, we call a function
const gatherCalculResult = (newResult) => {
array.push(newResult);
if (array.length === stuffs.length) {
callback(array);
}
};
// Function that makes the calculation for one stuff
const makeCalculation = (oneStuff) => {
if (condition) {
return gatherCalculResult(oneStuff);
}
// Get a stuff asynchronously
return api.compute(oneStuff, (resp) => {
gatherCalculResult(resp.stuff);
});
};
// We trigger all calculation
stuffs.forEach(x => x.makeCalculation(x));
你能解释这个背后的想法吗?它是否工作,因为最后的回报块?为什么不以另一种方式阻止呢? – aclokay
这是一个不好的做法,把异步代码进入一个循环。你应该创造一系列的承诺,然后是'Promise.all'。 (同意异步真棒!) –
它和瀑布一样,它有什么不好? – Lazyexpert
我同意@GrégoryNEUT,在处理异步代码时应避免循环。 –