for循环内的异步回调

时间:2020-01-14 07:26:07

标签: javascript asynchronous callback

as.character(Sys.time(), tz = 'Asia/Jakarta', usetz = TRUE)
# [1] "2020-01-14 14:25:47 WIB"

在上面的代码中, gtts.savetos3 是一个异步函数,由于需要花费大量的时间才能完成数组中每个元素的执行。我无法在 op 数组中打印完整的url数组,因为它会打印一个空数组。

gtts.savetos3 函数使用正确的url调用给定的回调,以便我可以使用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); }) 打印输出,但是在循环时我搞砸了。

我的问题是

  1. 如何使回调函数仅在执行后才被调用 所有数组元素都由 gtts.savetos3 函数处理。
  2. 在仅使用回调的帮助下,是否可以在没有 Promise.all 或没有 Promise 的情况下实现上述问题的解决方案。

预先感谢...!

2 个答案:

答案 0 :(得分:2)

您可以保留一个计数器,并在方法的回调中增加它, 仅在计数器达到以下长度时才调用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或任何第三方模块的情况下解决问题的一种方法,而不是优雅或正确的方法。

如果您要坚持使用回调并且可以使用第三方模块,请查看 Async waterfall method

如果您使用的是aws-sdk的{​​{1}},则sdk已经提供了一个 以及承诺的方法,您只需将方法附加到 s3 put object得到相同的结果。

要解决承诺问题,只需将包装器更改为 异步功能。

.promise

答案 1 :(得分:0)

这是我的解决方案。

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)
})