我如何保证多个承诺的解决方案顺序?

时间:2016-10-25 19:20:05

标签: javascript promise ecmascript-6 es6-promise

尝试学习一些现代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异步。并在完成后记录。在控制台中,它按预期显示:“即时”,“快速”,“慢速”和“完成”。

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

我怎样才能做到这一点?

6 个答案:

答案 0 :(得分:3)

部分问题是日志记录发生在setTimeout方法中,而不是实际来自promise解析。



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);
  console.log('finished');
}, (error) => {
  console.log(error);
});




将值传递给resolve方法将返回Promise.all中的所有内容。响应从每个promise作为数组返回,并且一旦完成,您就可以遍历这些响应。

答案 1 :(得分:3)

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

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



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




请注意,与cchamberlain' answer不同,此方法等待所有承诺在开始返回结果之前解析。它返回结果,但不违反您按顺序保存结果的要求。 (要验证这一点,请尝试将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'));




Try in Babel。注意:上述代码目前不适用于没有Babel的现代浏览器(截至2016年10月)。在未来的浏览器中它会。

答案 2 :(得分:2)

<强>已更新

您不能同时将它们全部打开,并希望结果以您当前代码的顺序登录。您可以执行以下操作:

&#13;
&#13;
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)
})
&#13;
&#13;
&#13;

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

答案 3 :(得分:0)

如果问题的要求是

  

“instant”在“慢”之前不会回显/记录

  

但与此同时,他们仍然必须同时开始   异步。

您只需要对传递给Promise.all()的可迭代对象中的元素进行重新排序,或者在.then()链接到Promise.all()之前调整结果数组,然后在结果的每个元素上调用console.log()阵列。

如果要求是

  

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

  

“我如何保证多个承诺的解决顺序?”

请参阅this Answer

  

Promise.all传递来自所有承诺的值数组   它被传递的可迭代对象。值数组维持着   原始可迭代对象的顺序,而不是承诺的顺序   解决了。​​如果迭代数组中传递的东西不是   保证,它由Promise.resolve转换为一个。

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

答案 4 :(得分:-1)

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

您可以利用函数调用返回Promise构造函数,将应传递给console.log()的值传递给resolve()reject()。将值推送到数组。使用.then()处理返回的Promise值,将返回的值推送到数组,将数组返回到链中下一个.then()的回调函数参数。访问链中最后Promise的{​​{1}}值的链式数组。

&#13;
&#13;
.then()
&#13;
&#13;
&#13;

答案 5 :(得分:-1)

首先,您的代码已经在&#34;同一时间&#34;开始所有3个承诺。您也正在记录&#34;已完成&#34;正确。根据我对该问题的理解,您希望按顺序处理承诺的结果,但让它们并行执行。

&#13;
&#13;
computer:Server user$ swift build -Xswiftc -I/usr/local/mysql/include -Xlinker -L/usr/local/mysql/lib -Xswiftc -DNOJSON
Linking CLibreSSL
Compile Swift Module 'TurnstileCrypto' (3 sources)
Compile Swift Module 'Jay' (21 sources)
Compile Swift Module 'SocksCore' (14 sources)
Compile Swift Module 'Polymorphic' (2 sources)
Compile Swift Module 'PathIndexable' (2 sources)
Compile Swift Module 'libc' (1 sources)
Compile Swift Module 'Core' (28 sources)
ld: warning: directory not found for option '-L/usr/local/mysql/lib'
Compile Swift Module 'Node' (22 sources)
Compile Swift Module 'Socks' (5 sources)
Compile Swift Module 'Fluent' (35 sources)
Compile Swift Module 'Essentials' (2 sources)
Compile Swift Module 'TLS' (7 sources)
Compile Swift Module 'Console' (34 sources)
Compile Swift Module 'Leaf' (34 sources)
Compile Swift Module 'JSON' (8 sources)
Compile Swift Module 'Turnstile' (13 sources)
Compile Swift Module 'Random' (3 sources)
Compile Swift Module 'Cipher' (2 sources)
Compile Swift Module 'MySQL' (10 sources)
Compile Swift Module 'TurnstileWeb' (8 sources)
Compile Swift Module 'BCrypt' (1 sources)
Compile Swift Module 'Hash' (3 sources)
Compile Swift Module 'HMAC' (2 sources)
Compile Swift Module 'FluentMySQL' (2 sources)
Compile Swift Module 'URI' (10 sources)
Compile Swift Module 'Transport' (8 sources)
Compile Swift Module 'HTTP' (33 sources)
Compile Swift Module 'SMTP' (21 sources)
Compile Swift Module 'WebSockets' (14 sources)
Compile Swift Module 'Settings' (10 sources)
Compile Swift Module 'Cookies' (11 sources)
Compile Swift Module 'Cache' (3 sources)
Compile Swift Module 'Routing' (9 sources)
Compile Swift Module 'HTTPRouting' (5 sources)
Compile Swift Module 'Sessions' (6 sources)
Compile Swift Module 'Auth' (14 sources)
Compile Swift Module 'TypeSafeRouting' (3 sources)
Compile Swift Module 'Vapor' (86 sources)
Compile Swift Module 'VaporMySQL' (1 sources)
Compile Swift Module 'App' (3 sources)
Linking ./.build/debug/App
ld: warning: directory not found for option '-L/usr/local/mysql/lib'
ld: library not found for -lmysqlclient for architecture x86_64
<unknown>:0: error: link command failed with exit code 1 (use -v to see invocation)
<unknown>:0: error: build had 1 command failures
error: exit(1): /Applications/Xcode/10.0/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift-build-tool -f /Users/user/test/Server/.build/debug.yaml
&#13;
&#13;
&#13;

这将保证您按顺序处理分辨率。

注意:在您的示例中,您使用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); });,保证按时间顺序调用处理程序,因此您现有的代码已经记录了&#34;即时& #34;,&#34;快速&#34;,&#34;慢&#34;,&#34;完成&#34;。我提供的代码保证了任何承诺集的顺序,具有不同的解析时间。