从嵌套循环按顺序执行异步处理功能

时间:2019-03-21 18:45:25

标签: javascript node.js

我有一个将大量数据保存在数据库中的功能。回调将在最后异步调用。

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专业人士的建议,您如何解决此类问题?

2 个答案:

答案 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
        }
      }
    }
  }
}

现在您的函数存在,您可以使用它,但是它是异步的,因此它在运行后不会停止任何代码,因此您应该执行以下两项操作之一:

  1. await您打给myFunc
  2. 的电话
  3. saveInDB中放置所有依赖于.then()的代码以首先完成
myFunc(/* your arrays */)
  .then(() => {
    // your function has finished
  })