蓝鸟“地图”早早回归吗?

时间:2016-11-15 20:50:48

标签: javascript promise bluebird

让我们假设我有10个运行的promise将传递给Promise.map(),其默认并发设置为3

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

map()的{​​{3}}声明如下:

  

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

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

修改

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

2 个答案:

答案 0 :(得分:5)

从字面上看,Bluebird的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);    
});                        

我的输出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 

正如您所料,所有承诺都已安排并运行,但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);                            
});                                  

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

答案 1 :(得分:2)

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

我有10个承诺,在超时后会被解决或拒绝。第4个(因为数组从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)
  })

这将产生:

> 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

所以,行为如下:

    只要被映射的一个承诺被拒绝,
  • Promise.map就会被短路。
  • map中的回调永远不会执行任何后续承诺。
  • 请注意,Error 3出现在意图较慢的承诺之前。
  • 但是,所有的承诺都会被“执行”,直到它们被解决。