【问题标题】:async.mapLimit with Promiseasync.mapLimit 与 Promise
【发布时间】:2019-12-28 13:18:52
【问题描述】:

我正在尝试使用异步模块 (v3),尤其是 async.mapLimit 方法来提交有限数量的并行异步请求。这适用于以下(简化)示例代码中的回调:

async = require('async');
async.mapLimit(['1','2','3','4','5'], 3, function(num, callback){
setTimeout(function(){
    num = num * 2,
    console.log(num);
    callback(null, num);
}, 
4000);  
},function(err, results){
    console.log(results);
});

结果我得到了单个值,最后得到了“结果”中所有值的数组:

[2,4,6,8,10]

现在我正在努力使用这种方法的基于 Promise 的版本。 The documentation 说如果我不提供回调,它会返回一个 Promise。如何将此基于回调的代码更改为使用 Promises?

我试过了,例如这个,但它只显示第一组请求(这是在 cmets 中的第一个建议之后更新的):

let numPromise = async.mapLimit(['1','2','3','4','5'], 3, function(num, callback){
    setTimeout(function(){
        num = num * 2,
        console.log(num);
        callback(null, num);
    }, 
    4000); 
});
Promise.all([numPromise]) //always calls .then immediately, without result
.then((result) => console.log("success:" + result))
.catch(() => console.log("no success"));

我确实正确地取回了所有单个值,但是“.then”会立即执行并给我一个“成功”和一个空的“结果”变量。

注意:我当然看过这个帖子ES6 Promise replacement of async.eachLimit / async.mapLimit,但我认为这不能回答我的问题。

PS:我已经找到了解决这个问题的其他方法,但我对如何正确使用这个模块非常感兴趣(使用简短、干净的代码)。

【问题讨论】:

  • 您说,“如果我不提供回调,它会返回一个 Promise”,但您仍在提供回调。把它放在外面,然后用链 .then() 代替。然后的回调将通过num。在回调内部,承诺 setTimeout 并返回结果承诺。我会写一个答案,但我在错误的设备上。
  • 非常感谢您对此的想法。但是,如果我没记错的话,那么我提供的不是回调参数,而是“Iteratee”(这也是一个异步函数)。这应该是正确的,但我会试一试。
  • 你是对的,第三个参数是 iteratee。第四个参数,主回调,如果省略会导致async.mapLimit() 返回承诺。 iteratee 仍然需要它的回调,它需要在你的第一个代码块中调用。
  • 你不需要Promise.all(),只需要numPromise.then(function(result) {...})
  • 用“异步”尝试了更多的东西,但没有用。甚至无法运行 async/await(如文档中所建议的那样);-) 顺便说一句,版本是最新的,所以应该没问题。不过,感谢所有提示,绝对有助于让我走上正轨! @Roamer-1888

标签: node.js promise async.js


【解决方案1】:

解决方案非常简单 - 虽然我仍然相信上面的代码应该可以正常工作(根据文档),但我发现还有另一个包可以使用 Promise:'promise-async'

所以我换了行

async = require('async');

async = require('promise-async');

现在上面的代码按预期工作了:

let numPromise = async.mapLimit(['1','2','3','4','5'], 3, function(num, callback){
    setTimeout(function(){
        num = num * 2,
        console.log(num);
        callback(null, num);
    }, 
    4000);
})
//Promise.all([numPromise]) //Promise.all is not needed
numPromise
.then((result) => console.log("success:" + result))
.catch(() => console.log("no success"));

返回

2
4
6
8
10
success:2,4,6,8,10

【讨论】:

  • 感谢@Roamer-1888 的所有提示,例如在 Iteratee 中保持回调而不需要 Promise.all (无论如何这更像是一条安全线;-))
【解决方案2】:

这可能是更好的答案,尽管另一种选择似乎也不错:

const async = require('async');
const delay = require('util').promisify(setTimeout);
const numPromise = async.mapLimit(['1','2','3','4','5'], 3, async num => delay(200).then(() => num*2))
// or const numPromise = async.mapLimit(['1','2','3','4','5'], 3, async num => {
//    await delay(200);
//    return num*2;
// })
numPromise.then(console.log)
// or numPromise.then((results) => console.log(results))

另请参阅 GitHub 上的此问题线程作为参考: GitHub: async.mapLimit does not return a Promise

我认为我的代码的问题出在 iteratee 函数中 - 或者最初它不是异步的,或者我假设使用“回调”而不是“返回”(或者可能两者都使用 ;-))。

【讨论】:

  • 如果文档中包含一两个示例,将会节省大量时间和麻烦。希望这会帮助其他人。
  • 在链接的问题中,我还收到确认这是一个错误。所以希望这可能会在即将发布的版本中得到解决。还有一个关于示例的线程,所以期待看到这方面的一些改进,因为我非常感谢异步库。
  • 很好,您已确认存在错误。很难想象.mapLimit() 是如何编码的,以使迭代者需要async 关键字。如果编码正确,则返回承诺的正常 Function 应该表现相同。只能认为在某处对AsyncFunction 进行了测试。奇怪!
猜你喜欢
  • 2017-10-09
  • 1970-01-01
  • 1970-01-01
  • 2015-08-04
  • 1970-01-01
  • 2018-01-16
  • 1970-01-01
  • 2017-04-04
  • 2016-07-15
相关资源
最近更新 更多