【问题标题】:Promise all async operations承诺所有异步操作
【发布时间】:2016-10-25 11:57:28
【问题描述】:

我有两个异步操作需要不同的时间来执行,比如说

1 .一个操作需要 1 秒执行
2.其他操作 10 秒执行

我想使用promise.all,这两个操作将并行执行(我知道在js中没有多线程的概念......) 并且都在同一个踏板上执行, 当我使用 promise all 时,我 预计 op1 将在 op2 之前完成 这不会发生......知道我在这里错过了什么吗? (可以说 op1 在我的服务器(1 秒) op2(10 秒)中保存一些小东西,当我在 1 秒后检查时,我没有看到 op1 在两个都完成后完成......)。 我知道承诺都将在两者都完成(解决)后完成。

Promise.all([op1, op2]).then(values => { 
  console.log(values);
}, reason => {
  console.log(reason)
});

【问题讨论】:

  • 你怎么知道 op1 在 op2 之前完成了?你能提供op1 和op2 的代码吗? Promise.all() 在数组中的 all 承诺(例如op1 和 op2)完成(解决/拒绝)之前不会解决。只有在两者都完成后,Promise.all() 才会解析并执行您在 .then() 中的代码
  • "没有发生" - 请出示您的实际代码并告诉我们什么没有发生
  • "当我在 1 秒后检查时,我没有看到 op1 完成" - 如果您想等待该操作,则不应在超时后“检查”然后使用op1.then(…)。
  • "我想用promise.all 两个操作会并行执行" 注意使用Promise.all跟操作是否有没有关系是并行执行的。它所做的只是给你一个承诺,当任一操作失败或两个操作都成功时,该承诺将被履行。
  • @JennyM 是的。无论是在op1().then(…) 或Promise.all([op1(), …]) 上下文或其他地方使用,op1() 的工作方式都相同。

标签: javascript asynchronous promise bluebird


【解决方案1】:

我想用promise.all这两个操作将并行执行...

请注意,使用Promise.all 与操作是否并行执行没有任何关系。它所做的只是给你一个承诺,当两个操作都成功或当 其中一个 操作失败时被拒绝。

让我们看看你的代码,见 cmets:

Promise.all([op1, op2]).then(values => { 
  // This will happen when BOTH op1 and op2 are done
  console.log(values);
}, reason => {
  // This will happen when EITHER op1 OR op2 fails
  console.log(reason);
});

因此,如果 op1 需要 1 秒,op2 需要 10 秒并且我们假设它们都成功,则您的回调将在 10 秒后执行(当 op2 完成时)。如果您知道op1 只需要一秒钟,那么很可能op1 在您的Promise.all 回调被调用前几秒钟就完成了。

如果您想在op1 完成时收到通知,请在op1 上使用then。您可以单独执行此操作,也可以在执行此操作的同时使用Promise.all 在两者都完成时收到通知。

这个例子,使用setTimeout来模拟动作,可以帮助你理解;在下面,op1 需要 100 毫秒,op2 需要 1000 毫秒。为简单起见,它假设两个操作都成功:

var start = Date.now();
var op1 = startOp1();
var op2 = startOp2();
op1.then(function() {
  // Fires when op1 is successful; doesn't care about op2
  console.log("op1 done after " + (Date.now() - start) + "ms");
});
op2.then(function() {
  // Fires when op2 is successful; doesn't care about op1
  console.log("op2 done after " + (Date.now() - start) + "ms");
});
Promise.all([op1, op2]).then(function() {
  // Fires when BOTH ops are successful
  console.log("both done after " + (Date.now() - start) + "ms");
});

function startOp1() {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve();
    }, 100);
  });
}
function startOp2(flag) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve();
    }, 1000);
  });
}

注意:你说这两个操作都是异步的,所以我在上面假设了。

【讨论】:

  • "所以如果 op1 需要 1 秒,而 op2 需要 10 秒..." ...并且其中一个或两个都阻塞,那么回调将 可能会在 11 秒后执行……:)
  • @deceze:OP 说它们都是异步的,我认为这意味着它们不会阻塞 JavaScript 线程。但是,是的,如果他们正在做的事情的性质意味着他们最终会被序列化(即使在 JavaScript 线程之外,他们都试图对同一个互斥的事情采取行动),那么他们自然会堆积起来。
  • 那么这两个操作什么时候开始,我问它,因为promise all 中没有多线程...?它如何确定在数组中启动哪个promise?
  • @JennyM: Promise.all 绝对不会启动进程;当您将他们的承诺传递给Promise.all 时,他们已经开始了。它们是由您为获得这些承诺而调用的任何东西开始的(上面的startOp1 和startOp2)。
  • 谢谢,但这很令人困惑,因为我将 then 放在数组中,并且直到调用所有承诺时它们才开始,然后所有承诺都应该在“并行”中调用它(从数组中)所以它同时调用两者吗? (事件循环?)
【解决方案2】:

当我使用 promise all 时,我希望 op1 会在 op2 之前完成,而这>不会发生......知道我在这里遗漏了什么吗?

数组块中的所有单个promise都异步执行,只有在所有promise都成功解决后才能到达.then()。

尝试分别在 op1 和 op2 的 timer 函数和 resolve 函数之间使用 console.log('op1 done') 和 console.log('op2 done')。在控制台上看到的输出将是:

    op1 done //after 1 sec
    op2 done //after 10 sec
    ['op1 done','op1 done'] //immediately follows the above one

这应该会让你相信异步的本质。还让我举一个更明显的例子,在下面的代码中从浏览器中保存了一个文本,其中 Promise p2 在 Promise p1 之前完成。在 5 分钟 (p1) 的时间段内;该文件(使用 p2)将在 .then() 执行之前保存在系统中

    var FileSaver = require('file-saver');

    var p1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 5 * 60 * 1000, 'Executed Promise p2');                         
    // 5 min timer
    }); 

    var p2 = new Promise((resolve, reject) => {
    var blob = new Blob(["Hello, world!"],
    {type:"text/plain;charset=utf-8"});                                                            
    FileSaver.saveAs(blob
    , "hello world.txt");
    // Not tested it; from page: https://github.com/eligrey/FileSaver.js/
    console.log('done with Promise p1');
    resolve('Executed Promise p1')
    }); 

    Promise.all([p1, p2]).then(values => { 
    console.log(values); // ['Executed Promise p1','Executed Promise p2'] 
    });

【讨论】:

    【解决方案3】:

    对于 op1 在 op2 之前完成,可以使用以下选项之一 - 1. Promise Chaining 解释here 2. ES6 中提供的生成器。 3. ES7提供的Async-Await

    因为 Promise.all() 确保不会一个接一个地并行执行。

    【讨论】:

      猜你喜欢
      • 2020-03-26
      • 1970-01-01
      • 1970-01-01
      • 2016-02-27
      • 1970-01-01
      • 1970-01-01
      • 2021-07-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多