如何保证多个Promise的解析顺序?

问题描述 投票:0回答:6

尝试学习一些现代 JS,特别是 ECMAScript 6 Promises。我正在玩这个简单的测试:

let slow = new Promise((resolve) => {
  setTimeout(function()
  {  
	console.log('slow');
	resolve();	
  }, 2000, 'slow');
});

let instant = new Promise((resolve) => {
	console.log('instant');
	resolve();	
});

let quick = new Promise((resolve) => {
  setTimeout(function()
  {  
	console.log('quick');
	resolve();	
  }, 1000, 'quick');
});

Promise.all([slow, instant, quick]).then(function(results) {
  console.log('finished');
}, function(error) {
  console.log(error);	
});

我想要的是同时异步启动所有 Promise。当它们全部完成时并记录。在控制台中,这按预期显示:“即时”、“快速”、“慢速”和“完成”。

但是,如果我想确保“即时”在“慢速”完成之前不会回显/记录怎么办?也就是说,我希望控制台记录“快”、“慢”、“即时”和“完成”......但同时,它们仍然必须同时异步启动。

我怎样才能实现这个目标?

javascript promise ecmascript-6 es6-promise
6个回答
4
投票

所以要明确一点,你想要在这里做的是立即启动所有的 Promise,并按每个 Promise 出现的特定顺序显示它们的结果,对吗?

在这种情况下,我可能会这样做:

let slow = new Promise((resolve) => {
  setTimeout(function()
  {
    // Rather than log here, we resolve to the value we want to log
    resolve('slow');
  }, 2000, 'slow');
});

let instant = new Promise((resolve) => {
    resolve('instant');  
});

let quick = new Promise((resolve) => {
  setTimeout(function()
  {  
    resolve('quick');  
  }, 1000, 'quick');
});

// All Promises are now running. Let's print the results...

// First wait for the result of `slow`...
slow.then((result) => {
  // Result received...
  console.log(result);
  
  // Now wait for the result of instant...
  instant.then((result) => {
    
    // Result received...
    console.log(result);
    
    // Now wait for the result of quick...
    quick.then((result) => {
      
      // Result received...
      console.log(result);
      
    }).then((result) => {
      // Done
      console.log('finished');
    });
  });
});

请注意,与 cchamberlainanswer 不同,此方法 等待所有 Promise 解决后再开始返回结果。它会返回输入的结果,但不会违反保持结果有序的要求。 (要验证这一点,请尝试将

quick
的等待时间更改为 2500 毫秒,并观察其结果在
instant
后 500 毫秒打印。)根据您的应用程序,这可能是可取的。

上面的代码有点乱,但幸运的是,使用 ES2017 中新的

async/await
语法,它可以变得更加清晰:

let slow = new Promise((resolve) => {
  setTimeout(function()
  {
    // Rather than log here, we resolve to the value we want to log
    resolve('slow');
  }, 2000, 'slow');
});

let instant = new Promise((resolve) => {
    resolve('instant');  
});

let quick = new Promise((resolve) => {
  setTimeout(function()
  {  
    resolve('quick');  
  }, 1000, 'quick');
});

// All Promises are now running. Let's print the results...

async function logResults(...promises) {
  for (let promise of promises) {
    console.log(await promise);
  }
}

logResults(slow, instant, quick).then(() => console.log('finished'));

尝试 Babel。注意:上述代码目前无法在没有 Babel 的现代浏览器中运行(截至 2016 年 10 月)。在未来的浏览器中它会的。


4
投票

问题的一部分是日志记录是在

setTimeout
方法中发生的,而不是实际上来自承诺解决方案。

const slow = new Promise((resolve) => {
  setTimeout(() => {
    console.log('slow - from setTimeout');
    resolve('slow - from resolve');
  }, 2000, 'slow');
});

const instant = new Promise((resolve) => {
  console.log('instant - from setTimeout');
  resolve('instant - from resolve');
});

const quick = new Promise((resolve) => {
  setTimeout(() => {
    console.log('quick - from setTimeout');
    resolve('quick -from resolve');
  }, 1000, 'quick');
});

Promise.all([slow, instant, quick]).then((results) => {
  console.log('results -', results);
  console.log('finished');
}, (error) => {
  console.log(error);
});

将值传递给

resolve
方法将返回
Promise.all
中的所有内容。每个 Promise 都会以数组形式返回响应,一旦所有响应完成,您就可以迭代这些响应。


2
投票

已更新

您不能同时启动它们并期望结果按照您使用当前代码要求的顺序记录。您可以执行以下操作:

let slow = new Promise((resolve) => {
  setTimeout(() => resolve('slow'), 2000)
})

let instant = new Promise((resolve) => {
  // In the future setImmediate can be used here to ensure async execution. For now, setTimeout with 0MS effectively does the same thing.
  setTimeout(() => resolve('instant'), 0)
})

let quick = new Promise((resolve) => {
  setTimeout(() => resolve('quick'), 1000)
})

Promise.all([slow, instant, quick]).then(function(results) {
  for(let result of results) {
    console.log(result)
  }
  console.log('finished')
}, function(err) {
  console.error(err)
})

这会将它们全部安排好,然后在完成后按正确的顺序打印。


0
投票

如果问题的要求是

“即时”不会在“慢速”之前回显/记录

但同时,它们仍然必须同时开始 异步。

您只需要对传递给

Promise.all()
的可迭代对象中的元素进行重新排序,或者在对结果数组的每个元素调用
.then()
之前调整链接到
Promise.all()
console.log()
中的结果数组。

如果要求是

“如何等待另一个承诺?”

“如何保证多个 Promise 的解析顺序?”

参见这个答案


Promise.all
传递来自所有 Promise 的值数组 它被传递的可迭代对象。值数组维护 原始可迭代对象的顺序,而不是承诺的顺序 已解决。如果可迭代数组中传递的内容不是 保证,它会被
Promise.resolve
转换为 1。

let slow = new Promise((resolve) => {
  setTimeout(function(value) {  
	resolve(value);	
  }, 2000, "slow");
});

let instant = new Promise((resolve) => {
	resolve("instant");	
});

let quick = new Promise((resolve) => {
  setTimeout(function(value) {  
	resolve(value);	
  }, 1000, "quick");
});

Promise.all([slow, instant, quick]).then(function(results) {
  console.log("finished");
  console.log(results.join("\n"))
}, function(error) {
  console.log(error);	
});


-1
投票

首先,您的代码已经“同时”启动了所有 3 个 Promise。您还正确记录了“完成”。根据我对问题的理解,您想要按顺序处理承诺的结果,但让它们并行执行。

let slow = new Promise((resolve) => {
  setTimeout(function()
  {  
    resolve();
  }, 2000);
});

let instant = new Promise((resolve) => {
    resolve();
});

let quick = new Promise((resolve) => {
  setTimeout(function()
  {  
    resolve();
  }, 1000);
});

instant.then(function(results) {
  console.log("instant");
}).then(function(){return quick;}).then(function(results) {
  console.log("quick");
}).then(function(){return slow;}).then(function(results) {
  console.log("slow");
}).then(function(){ return Promise.all([slow, instant, quick]);}).then(function(results) {
  console.log('finished');
}).catch(function(error) {
  console.log(error);   
});

这将保证您能够按顺序处理决议。

注意:在您的示例中,您使用

setTimeout
,它保证按时间顺序调用处理程序,因此您现有的代码将已经记录“即时”,“快速”,“慢速”,“完成” ”。我提供的代码保证了具有不同解析时间的any一组承诺的顺序。


-1
投票

Promise.all()
不需要返回预期结果。

您可以利用函数调用返回

Promise
构造函数,将应传递给
console.log()
的值传递给
resolve()
reject()
。将值推入数组。使用
.then()
处理返回的
Promise
值,将返回值压入数组,将数组返回给链中下一个
.then()
的回调函数参数。访问链中最后一个
Promise
.then()
值的链式数组。

let results = [];

let pace = value => {console.log(value); results.push(value); return results};

let slow = () => new Promise((resolve) => {
  setTimeout((value) => {  
    resolve(value);  
  }, 2000, "slow");
});

let instant = () => new Promise((resolve) => {
    resolve("instant");  
});

let quick = () => new Promise((resolve) => {
  setTimeout((value) => {  
    resolve(value);  
  }, 1000, "quick");
});

slow().then(pace)
.then(instant).then(pace)
.then(quick).then(pace)
.then(res => console.log("finished, results:", res))
.catch(error => console.log(error));

© www.soinside.com 2019 - 2024. All rights reserved.