我有一个将大量数据保存在数据库中的功能。回调将在最后异步调用。
function process(..., fn) {
saveInDB(function(err, results) {
// ...
// fn() or fn(err)
})
}
该函数从嵌套循环中被多次调用。
for (const x of arrays) {
const space1 = x[0]
for (const y of x.slice(1)) {
const space2 = y[0]
for (const z of y[1]) {
process(space1, space2, z, fn)
}
}
}
该问题要求仅在上一次成功时才进行下一次调用。这是我繁琐的实现。
let calls = []
for (const x of arrays) {
const space1 = x[0]
for (const y of x.slice(1)) {
const space2 = y[0]
for (const z of y[1]) {
calls.push((fn) => () => process(space1, space2, z, fn))
}
}
}
let call = null
for (let i = calls.length - 1; i >= 0; --i) {
if (i === calls.length - 1) {
call = calls[i](err => {
if (!err)
return finalCallback(null, { 'status': 'success' })
log.error(err)
finalCallback(err)
})
continue
}
const lastNext = call
call = calls[i](err => {
if (!err)
return lastNext()
finalCallback(err)
log.error(err)
})
}
if (call)
call()
我正在寻求Javascript专业人士的建议,您如何解决此类问题?
答案 0 :(得分:1)
saveToDB
通常会采用一些表示数据的参数;我只是假设它需要一个数据参数和一个回调,但是可以根据需要进行调整。
首先实现该功能。您使用的API可能已经支持了promise,这意味着如果未将回调函数传递给它,则上述函数将返回promise。但是,如果不是这种情况,则可以创建自己的承诺函数:
// promisify the saveInDB function:
const process = (data) => new Promise((resolve, reject) =>
saveInDB(data, (err, results) => err ? reject(error) : resolve(results))
);
然后创建一个async
函数,以便您可以使用await
:
async function task(arrays) {
for (const x of arrays) {
const space1 = x[0]
for (const y of x.slice(1)) {
const space2 = y[0]
for (const z of y[1]) {
await process([space1, space2, z])
}
}
}
}
...然后调用它。它会返回一个承诺,因此您可以应对实现和拒绝:
task(arrays).then(() => console.log("all done"))
.catch((err) => console.log("error occurred", err));
答案 1 :(得分:1)
async ... await
在您的用例中,使用await
关键字将使您等待process
返回的承诺得以解决,然后再继续。您必须将函数定义为async
。
您还需要使用try ... catch
块来处理任何错误。
由于您的process
函数当前未返回承诺,因此您需要对其进行修改。
示例:
function process(/* your args */) {
return new Promise((resolve, reject) => {
saveInDB((err, results) => {
if (err) {
reject(err)
} else {
resolve(results)
}
})
}
// now for the `async ... await`
async function myFunc(arrays) {
for (const x of arrays) {
const space1 = x[0]
for (const y of x.slice(1)) {
const space2 = y[0]
for (const z of y[1]) {
try {
// This will wait until your `process` has finished
await process(space1, space2, z, fn)
} catch (error) {
// handle any errors
console.log(error)
// if you would like to bail after an error you can `return`
return
}
}
}
}
}
现在您的函数存在,您可以使用它,但是它是异步的,因此它在运行后不会停止任何代码,因此您应该执行以下两项操作之一:
await
您打给myFunc
或saveInDB
中放置所有依赖于.then()
的代码以首先完成myFunc(/* your arrays */)
.then(() => {
// your function has finished
})