与Promise.all并行运行?

时间:2017-03-13 20:00:43

标签: node.js promise bluebird

我开始相信Promise.all会并行执行你传递给它的所有函数,并不关心返回的promises完成的顺序。

但是当我写这个测试代码时:

function Promise1(){
    return new Promise(function(resolve, reject){
        for(let i = 0; i < 10; i++){
            console.log("Done Err!");
        }
        resolve(true)
    })
}

function Promise2(){
    return new Promise(function(resolve, reject){
        for(let i = 0; i < 10; i++){
            console.log("Done True!");
        }
        resolve(true)
    })
}

Promise.all([ 
    Promise1(),
    Promise2()
])
.then(function(){
    console.log("All Done!")
})

我得到的结果就是这个

Done Err!
Done Err!
Done Err!
Done Err!
Done Err!
Done Err!
Done Err!
Done Err!
Done Err!
Done Err!
Done True!
Done True!
Done True!
Done True!
Done True!
Done True!
Done True!
Done True!
Done True!
Done True!
Done!

但如果他们并行运行我不希望他们同时执行并给我这样的结果吗?

Done Err!
Done True!
Done Err!
Done True!
Done Err!
Done True!
Done Err!
Done True!
Etc. Etc.?

或者我错过了一些我正在做的事情?

5 个答案:

答案 0 :(得分:10)

这是因为你的Promise是阻塞和同步的!尝试使用超时而不是同步循环:

function randomResolve(name) {
  return new Promise(resolve => setTimeout(() => {
    console.log(name);
    resolve();
  }, 100 * Math.random()));
}

Promise.all([ 
    randomResolve(1),
    randomResolve(2),
    randomResolve(3),
    randomResolve(4),
])
.then(function(){
    console.log("All Done!")
})

答案 1 :(得分:1)

我建议这样使用它:

const [
    res1,
    res2
] = await Promise.all([
    asyncCall1(),
    asyncCall1(),
]);

答案 2 :(得分:0)

非串行执行非异步主体 当你到达身体内的异步调用时(例如,点击一个URL),数组中的其他Promise将开始执行。

答案 3 :(得分:0)

要以约翰内斯·梅尔茨(Johannes Merz)开始的工作为基础,我建议使用以下代码来阐明事情是并行发生的。

JS是单线程的,但是Node.js有很多工具可以显式和隐式地启动其他线程。承诺公开了我们经常需要的更多功能,而不必显式启动新线程或进程。 Promise.all()就是这样的示例,但是您需要对Promises感到满意,才能使用它而不会给自己造成严重的麻烦,例如Promise Scope内存泄漏。

function randomResolve(name,t) {
  return new Promise(resolve => setTimeout(() => {
    console.log({ name, t });
    resolve({ name, t });
  }, t));
}

(() => {
    // Get epoch time before starting so we can confirm the execution time reflects our slowest timeout
    let start = new Date().valueOf(); 

    Promise.all([ 
        randomResolve(1, 1000 * Math.random()),
        randomResolve(2, 1000 * Math.random()),
        randomResolve(3, 1000 * Math.random()),
        randomResolve(4, 1000 * Math.random()),
    ])
    .then(function( res ){
        console.info( res );
        console.log("All Done!", parseInt(new Date().valueOf() - start) );
    })
})();

此模式采用输入数组,并使用array.map()取回已启动的Promise数组,该数组将按上述方式并行处理。注意这里没有使用async / await。

function randomResolve(name,t) {
  return new Promise(resolve => setTimeout(() => {
    console.log({ name, t });
    resolve({ name, t });
  }, t));
}

(() => {
    // Get epoch time before starting so we can confirm the execution time reflects our slowest timeout
    let start = new Date().valueOf(),
        vals = [ 
            [1, 1000 * Math.random()],
            [2, 1000 * Math.random()], 
            [3, 1000 * Math.random()],
            [4, 1000 * Math.random()]
        ];

    Promise.all( vals.map( v => { return randomResolve(v[0], v[1] ); } ) )
    .then(function( res ){
        console.info( res );
        console.log("All Done!", parseInt(new Date().valueOf() - start) );
    })
})();

此版本确实实现了异步/等待。

function randomResolve(name,t) {
  return new Promise(resolve => setTimeout(() => {
    console.log({ name, t });
    resolve({ name, t });
  }, t));
}

(async () => {
    // Get epoch time before starting so we can confirm the execution time reflects our slowest timeout
    let start = new Date().valueOf(),
        vals = [ 
            [1, 1000 * Math.random()],
            [2, 1000 * Math.random()], 
            [3, 1000 * Math.random()],
            [4, 1000 * Math.random()]
        ];

    let res = await Promise.all( vals.map( async v => { return await randomResolve( v[0], v[1] ); } ) );
    // await the Promise.aall() call instead of using .then() afterwards with another closure then
    //     forEach v in vals, start and await a Promise from randomResolve() then return the result to map

    console.info( res );
    console.log("All Done!", parseInt(new Date().valueOf() - start) );

})();

答案 4 :(得分:-1)

也许解决方案是使用工人农场,我不知道如何解释它,因为我是NodeJS的新手,但是这里有一篇有趣的文章:

https://blog.logrocket.com/node-js-multithreading-what-are-worker-threads-and-why-do-they-matter-48ab102f8b10/

在这种情况下,这是使用工作人员农场的方法
(目前我对这个主题没有很好的了解,因此请随时纠正我。)

首先,安装“工人农场”

npm install --save worker-farm

然后:

// index.js
const workerFarm = require("worker-farm");
const service = workerFarm(require.resolve("./service"));
function Promise1() {
  return new Promise(function(resolve, reject) {
    service("promise1", (err, output) => {
      resolve(true);
    });
  });
}

function Promise2() {
  return new Promise(function(resolve, reject) {
    service("promise2", (err, output) => {
      resolve(true);
    });
  });
}

Promise.all([Promise1(), Promise2()]).then(function() {
  console.log("All Done!");
});

service.js中创建一个需要花费大量执行时间的函数,一旦执行完成,便执行回调。

// service.js
const blocker = (input, callback) => {
  // Number loop turns
  // Adjust this number depending on your CPU
  const nbTurn = 1000000000;
  // How many log to display during the loop
  const nbReminder = 4;
  let i;
  for (i = 0; i <= nbTurn; i++) {
    const remainder = (i % Math.ceil(nbTurn / nbReminder)) / 100;
    if (remainder === 0) {
      console.log(input, i);
    }
  }
  console.log(input + "end", i);
  callback(null, nbTurn);
};
module.exports = blocker;

编辑:我找到了另一种解决方案:napajsworking example on codesandbox