蓝鸟"地图"早早回归吗?

Hen*_*los 4 javascript promise bluebird

让我们假设我有10个Promises正在运行,Promise.map()它的默认并发设置为3.

如果前3个承诺中的任何一个被拒绝,其他7个承诺是否会被启动?

蓝鸟的文档map()状态如下:

等待映射器函数返回的Promise,并且在所有映射的promise都已满足之前,返回的promise不会实现.如果数组中的任何promise被拒绝,或者mapper函数返回的任何promise都被拒绝,那么返回的promise也会被拒绝.

它只表明,如果一切都满足,那么等待内心的承诺,但我不清楚如果其中任何一个遭到拒绝会发生什么.

编辑

我知道map函数的规范定义是输出的长度与输入的大小相同,但我不确定Bluebird是否尊重它.

ssu*_*ube 5

从字面上看,蓝鸟的立刻Promise.prototype.map回归.

执行此操作时,它会返回Promise可能无法立即解决的问题.我想你真的想知道这个承诺是如何表现的,并且有一些事情需要解决:

如果前3个承诺中的任何一个被拒绝,其他7个承诺是否会被启动?

是.Promise在您创建时"已启动"(即已安排).其他7人将尝试解决或可能足以让你需要假设他们会这样做.

想象一下,如果浏览器只允许4个HTTP连接到服务器并且您发出10个请求.那些第一个(失败的)3将和一个朋友一起被发送,他可能不会失败但肯定会跑.

你应该假设所有的承诺都会调用他们的身体.

它只表明,如果一切都满足,那么等待内心的承诺,但我不清楚如果其中任何一个遭到拒绝会发生什么.

这很容易测试:

const Promise = require('bluebird');                    

function delayReject(delay, err) {                      
  return new Promise((res, rej) => {                    
    console.log('waiting to reject', err);              
    setTimeout(() => rej(err), delay);                  
  });                                                   
}                                                       

function delayValue(delay, val) {                       
  return new Promise((res, rej) => {                    
    console.log('waiting to resolve', val);             
    setTimeout(() => res(val), delay);                  
  });                                                   
}                                                       

const promises = [1, 2, 3, 4, 5, 6, 7, 8, 9].map(it => {
  if (it % 3 === 0) {                                   
    return delayReject(50, it);                         
  } else {                                              
    return delayValue(50, it);                          
  }                                                     
});                                                     

Promise.map(promises, v => {                            
  console.log('mapping', v);                            
  return -v;                                            
}).then(it => {                                         
  console.log('mapped', it);                            
}).catch(err => {                                       
  console.log('error', err);    
});                        
Run Code Online (Sandbox Code Playgroud)

我的输出node v6.8.1是:

ssube@localhost ~/questions/40619451 $  > node early-exit.js
waiting to resolve 1                                                      
waiting to resolve 2                                                      
waiting to reject 3                                                       
waiting to resolve 4                                                      
waiting to resolve 5                                                      
waiting to reject 6                                                       
waiting to resolve 7                                                      
waiting to resolve 8                                                      
waiting to reject 9                                                       
mapping 1                                                                 
mapping 2                                                                 
error 3 
Run Code Online (Sandbox Code Playgroud)

正如您所料,所有承诺都已安排并运行,但map在第一次失败后,它们会停止运行.

Bluebird文档提到:

尽可能快地调用给定项的映射器函数,也就是说,当满足输入数组中该项的索引的承诺时.这并不意味着结果数组具有随机顺序的项,这意味着.map可以用于并发协调.all.

这表明映射项的顺序可能不会持久化,就像在上面的示例中一样.我们可以通过在延迟中添加一些噪声来测试它:

const Promise = require('bluebird');                    

function delayNoise(n) {                                
  return n + Math.floor(Math.random() * 50);            
}                                                       

function delayReject(delay, err) {                      
  return new Promise((res, rej) => {                    
    console.log('waiting to reject', err);              
    setTimeout(() => rej(err), delayNoise(delay));      
  });                                                   
}                                                       

function delayValue(delay, val) {                       
  return new Promise((res, rej) => {                    
    console.log('waiting to resolve', val);             
    setTimeout(() => res(val), delayNoise(delay));      
  });                                                   
}                                                       

const promises = [1, 2, 3, 4, 5, 6, 7, 8, 9].map(it => {
  if (it % 3 === 0) {                                   
    return delayReject(50, it);                         
  } else {                                              
    return delayValue(50, it);                          
  }                                                     
});                                                     

Promise.map(promises, v => {                            
  console.log('mapping', v);                            
  return -v;                                            
}).then(it => {                                         
  console.log('mapped', it);                            
}).catch(err => {                                       
  console.log('error', err);                            
});                                  
Run Code Online (Sandbox Code Playgroud)

运行会产生更有趣的结果:如果第一个承诺拒绝,则地图结束并且不会尝试映射其他地图.正如你猜测的那样,它会发生短路.


Hen*_*los 2

我取得了与@ssube 的答案非常相似的结果。

我有 10 个承诺,这些承诺将在超时时间增加后得到解决或拒绝。第四个(因为数组是从 0 开始的)被拒绝。

const Promise = require('bluebird')

function delay(timeout, err, i) {
  return new Promise(function (resolve, reject) {
    if (err) {
      setTimeout(function () {
        console.log('Rejected', err.message)
        reject(err)
      }, timeout)
    } else {
      setTimeout(function () {
        console.log('Resolved', i)
        resolve(i)
      }, timeout)
    }
  })
}

const promises = Array.apply(null, {length: 10})
  .map(Function.call, Number)
  .map(function (it) {
    if (it === 3) {
      return delay(500 * it, new Error(it))
    } else {
      return delay(500 * it, null, it)
    }
  })

Promise.map(promises, function (p) {
  console.log('Mapping', p)
  return p.toString()
})
  .then(function (it) {
    console.log('All resolved', it)
  })
  .catch(function (err) {
    console.log('Error', err.message)
  })
Run Code Online (Sandbox Code Playgroud)

这将产生:

> Resolved 0
> Mapping 0
> Resolved 1
> Mapping 1
> Resolved 2
> Mapping 2
> Rejected 3
> Error 3
> Resolved 4
> Resolved 5
> Resolved 6
> Resolved 7
> Resolved 8
> Resolved 9
Run Code Online (Sandbox Code Playgroud)

因此,行为如下:

  • Promise.map每当被映射的承诺之一被拒绝时,就会短路。
  • map对于任何后续的承诺,永远不会执行回调 in 。
  • 请注意,它Error 3出现在故意放慢的承诺之前。
  • 然而,所有的承诺都会被“执行”,直到它们得到解决。