让我们假设我有10个运行的promise将传递给Promise.map()
,其默认并发设置为3
。
如果前3个承诺中的任何一个被拒绝,其他7个承诺是否会被启动?
map()
的{{3}}声明如下:
等待mapper函数返回的Promise,并且在所有映射的promise都已满足之前,返回的promise也不会实现。如果数组中的任何promise被拒绝,或者mapper函数返回的任何promise都被拒绝,那么返回的promise也会被拒绝。
它只表明,如果所有人都满足,那么等待内心的承诺,但我不清楚如果其中任何一个遭到拒绝会发生什么。
我知道map
函数的规范定义是输出的长度与输入的大小相同,但我不确定Bluebird是否尊重它。
答案 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
出现在意图较慢的承诺之前。