асинхронные обратные вызовы внутри для цикла - PullRequest
0 голосов
/ 14 января 2020
var a = ['url1', 'url2', 'url3'];
var op = [];

cb = (callback) => {
  for (var i = 0; i < a.length; i++) {
    gtts.savetos3(`${a[i]}.mp3`, a[i], 'ta', function(url) {
      console.log(url['Location']);
      op.push(url['Location']);
    });
  }
  callback()
}

cb(() => {
   console.log(op);
})

В приведенном выше коде gtts.savetos3 является асинхронной функцией . Это занимает значительное время для завершения выполнения для каждого элемента в массиве. Из-за асинхронного Я не могу напечатать полный массив URL-адресов в массиве op , так как он печатает пустой массив.

gtts.savetos3 функция вызывает указанный обратный вызов с правильным URL-адресом, так что Я могу напечатать вывод, используя console.log, но когда дело доходит до циклов, я запутался.

Мой вопрос

  1. Как сделать функцию обратного вызова вызываемой только после выполнения всех элементов массива, обработанных функцией gtts.savetos3 .
  2. , мы можем достичь решения вышеуказанной проблемы без Promise.all или без Обещание с помощью использования только обратных вызовов .

Заранее спасибо ...!

Ответы [ 2 ]

2 голосов
/ 14 января 2020

Вы можете хранить счетчик и увеличивать его в обратном вызове методов, вызывать обратный вызов done только тогда, когда счетчик достигнет длины массива.

cb = (done) => {
    let counter = 0;
    for (let i = 0; i < a.length; i++) {
        gtts.savetos3(`${a[i]}.mp3`, a[i], 'ta', function (url) {
            console.log(url['Location']);
            op.push(url['Location']);
            ++counter;
            if (counter == a.length) {
              done();
            }
        });
    }
}

cb(() => {
    console.log(op);
})

Это просто способ решить проблему без Promises или какого-либо стороннего модуля, но не элегантным или правильным способом.

Если вы хотите придерживаться обратного вызова и можете использовать сторонний модуль посмотрите Asyn c waterfall method.

Если вы используете aws-sdk s s3 put object, то sdk уже предоставляет многообещающие методы, вы можете просто добавьте свой метод с помощью .promise, чтобы получить то же самое.

Чтобы решить проблему с обещаниями, просто измените свою оболочку на асин c функцию.

async savetos3(...parametres) {
    //Some implementation
    let res = await S3.putObject(....params).promise();
    //Some implementation
}

cb = Promise.all(a.map(name => savetos3(`${name}.mp3`, name , 'ta')));

cb.then(() => {
    console.log(op);
})
0 голосов
/ 14 января 2020

Вот мое решение.

const a = ['url1', 'url2', 'url3'];
const op = [];

const saveToS3 = name => new Promise((resolve, reject) => {
    gtts.savetos3(`${name}.mp3`, name, 'ta', function (url) {
        console.log(url['Location']);
        resolve(url)
    });
})

Promise.all(a.map(item => saveToS3(item))).then(() => {
    console.log(op)
})
...