JavaScript асинхронный в цикле с обратными вызовами - PullRequest
0 голосов
/ 02 июля 2018

У меня сложная ситуация, когда необходимо собрать ключи, принадлежащие к определенным типам (типам в данном массиве), затем отфильтровать собранные ключи и перейти к функции удаления.

Процесс сбора вызывает шелл-коды и обрабатывает результаты в обратном вызове внутри цикла. Мне нужно будет подождать, пока завершится весь цикл обратного вызова, а затем перейти к функции удаления.

Я использую shelljs в кодах узлов, в основном это выглядит так:

var del_arr = [];

for (var i in types) {
  shell.exec(somecode with
    var [i], {
      silent: true
    },
    function(code, stdout, stderr) {
      somecode-processing/filtering stdout and pushes the results to del_arr;
    });
  //loop through array types[] and need to wait for all shell codes' callbacks to finish;
}

//then pass del_arr to deletion function

Мне не удалось создать асинхронную функцию в этом формате с помощью обратного вызова shelljs. Я также не знаю, как использовать обещание в этой ситуации.

Можете ли вы сказать мне, как добиться этого неблокирующего процесса? Спасибо

Ответы [ 4 ]

0 голосов
/ 03 июля 2018

Вы также можете использовать пакет async в нпм. Он предоставляет функцию eachSeries, которая может пригодиться в вашей ситуации, без использования обещаний и работы только с обратными вызовами.

async.eachSeries(hugeArray, function iteratee(item, callback) {
    if (inCache(item)) {
        callback(null, cache[item]); // if many items are cached, you'll overflow
    } else {
        doSomeIO(item, callback);
    }
}, function done() {
    //...
});

Подробнее о том, как использовать эту функцию: https://caolan.github.io/async/

0 голосов
/ 02 июля 2018

Попробуйте конвертировать shell.exec в Promise, например

function shellPromise(command,option) {
  return Promise((resolv,reject)=>{
      shell.exec(command,option,(code,stdout,stderr)=>
            resolv({code:code,stdout:stdout,stderr:stderr})
      );
   };
};

Тогда вы можете использовать что-то вроде

for (var i in types){
    var result=await shellPromise(somecode with var[i], {silent:true});
    // somecode-processing/filtering stdout and pushes the results to del_arr;
}
0 голосов
/ 02 июля 2018

Хорошая реализация этого случая:

async function myAsyncFunction() {
  const promises = types.map((type) => myAsyncRequest(type));
  let del_arr = Promise.all(promises);
}

Хорошая статья, которая объясняет это:

https://medium.freecodecamp.org/avoiding-the-async-await-hell-c77a0fb71c4c

0 голосов
/ 02 июля 2018

Превратите child_process.exec в обещание:

function execWrapper(command, options) {
  return new Promise((resolve, reject) => {
     shell.exec(command, options, (error, out, err) => {
       if (error) return reject(error);
       resolve({out: out, err: err});
     })
  })
}

Затем вы можете перебирать типы и сопоставлять каждый из них с обещанием:

const promises = types.map(type => execWrapper(type, {slient: true}));

Теперь дождитесь разрешения каждого обещания или отклонения одного:

Promise.all(promises).then((del_arr) => {
  // del_arr is now a array of objects with the stdout and stderr of each type.
  // 
})
...