node.js: как использовать последовательность и обещание моделировать два цикла aync - PullRequest
0 голосов
/ 01 октября 2018

У меня есть две функции в 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.Я могу сделать это, используя адские пирамиды обратного вызова со счетчиками для отслеживания завершения обратного вызова.Но я хочу использовать последовательность и обещаю упростить мой код.Как мне сделать это для вышеупомянутого?Я не могу понять, как это сделать с помощью функций, вызываемых циклом.

Ответы [ 3 ]

0 голосов
/ 01 октября 2018

После создания обещанной версии func_a() и func_b() вы можете использовать Promise.all() и await агрегированные результаты в async function без использования счетчика:

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.

0 голосов
/ 01 октября 2018

Вы пробовали util.promisify (оригинал) ?

Код, который вы упомянули, может быть преобразован в что-то вроде:

// 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.
}
0 голосов
/ 01 октября 2018

Вы можете использовать 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")
        }
    })();
...