如何使用 Promise.all 避免 promise 构造函数反模式
How do you avoid the promise constructor antipattern with Promise.all
在使用多个 promise 和 Promise.all
时如何避免 promise 构造函数反模式?
假设我有以下代码:
getFoo = function() {
return new Promise(function(resolve, reject) {
var promises = [];
promises.push(new Promise(function(resolve, reject) => {
getBar1().then(function(bar1) {
processBar1(bar1);
resolve(bar1);
});
}));
promises.push(new Promise(function(resolve, reject) => {
getBar2().then(function(bar2) {
processBar2(bar2);
resolve(bar2);
});
}));
Promise.all(promises).spread(function(bar1, bar2) {
var result = processBothBars(bar1, bar2);
resolve(result);
});
});
}
它提出了反模式的一些基本问题,错误被吞没,厄运金字塔。
顺便说一句,我正在使用蓝鸟。
您可以一起删除 new Promise
。
getFoo = function() {
var promises = [];
promises.push(getBar1().then(function(bar1) {
processBar1(bar1);
return bar1;
}));
promises.push(getBar2().then(function(bar2) {
processBar2(bar2);
return bar2;
}));
return Promise.all(promises).spread(function(bar1, bar2) {
var result = processBothBars(bar1, bar2);
return result;
});
}
// start mock
function getBar1() {
return Promise.resolve({name:'bar1',processed: false});
}
function getBar2() {
return Promise.resolve({name:'bar2',processed: false});
}
function processBar1(bar1) {
bar1.processed = true;
}
function processBar2(bar2) {
bar2.processed = true;
}
function processBothBars (bar1, bar2) {
return [bar1, bar2].filter(function (bar) {
return bar.processed;
}).map(function (bar) {
return bar.name;
});
}
Promise.prototype.spread = function (fn) {
return this.then(function (arr) {
return fn.apply(this, arr);
});
};
// end mock
var getFoo = function (fail) {
var promises = [];
promises.push(getBar1().then(function (bar1) {
processBar1(bar1);
if (fail) {
throw 'getBar1 Failed!';
}
return bar1;
}));
promises.push(getBar2().then(function (bar2) {
processBar2(bar2);
return bar2;
}));
return Promise.all(promises).spread(function (bar1, bar2) {
var result = processBothBars(bar1, bar2);
return result;
});
}
getFoo().then(function (result) {
console.log(result); // ['bar1', 'bar2']
});
getFoo(true).then(function (result) {
console.log(result); // doesn't happen
}).catch(function (e) {
console.error(e); // Error: getBar1 Failed!
});
.then
returns 一个承诺,所以没有必要创建一个新的包装它,除非你想防止错误到达外部承诺。
无需在这里创建您自己的任何承诺,因为 getBar1()
和 getBar2()
都已经 return 承诺 - 至少我们假设是这样,因为两者都是可行的。
提供processBar1
和processBar2
每个return你感兴趣的结果,代码将简化如下:
var getFoo = function() {
// write promises as an array literal
var promises = [
getBar1().then(processBar1),//result returned by getBar1() is automatically passed to processBar1
getBar2().then(processBar2) // ... ditto ...
];
return Promise.all(promises).spread(processBothBars);
};
Fwiw bluebird 证明了这一点:
getFoo = function() {
return Promise.join(getBar1().tap(processBar1),
getBar2().tap(processBar2),
processBothBars);
}
在使用多个 promise 和 Promise.all
时如何避免 promise 构造函数反模式?
假设我有以下代码:
getFoo = function() {
return new Promise(function(resolve, reject) {
var promises = [];
promises.push(new Promise(function(resolve, reject) => {
getBar1().then(function(bar1) {
processBar1(bar1);
resolve(bar1);
});
}));
promises.push(new Promise(function(resolve, reject) => {
getBar2().then(function(bar2) {
processBar2(bar2);
resolve(bar2);
});
}));
Promise.all(promises).spread(function(bar1, bar2) {
var result = processBothBars(bar1, bar2);
resolve(result);
});
});
}
它提出了反模式的一些基本问题,错误被吞没,厄运金字塔。
顺便说一句,我正在使用蓝鸟。
您可以一起删除 new Promise
。
getFoo = function() {
var promises = [];
promises.push(getBar1().then(function(bar1) {
processBar1(bar1);
return bar1;
}));
promises.push(getBar2().then(function(bar2) {
processBar2(bar2);
return bar2;
}));
return Promise.all(promises).spread(function(bar1, bar2) {
var result = processBothBars(bar1, bar2);
return result;
});
}
// start mock
function getBar1() {
return Promise.resolve({name:'bar1',processed: false});
}
function getBar2() {
return Promise.resolve({name:'bar2',processed: false});
}
function processBar1(bar1) {
bar1.processed = true;
}
function processBar2(bar2) {
bar2.processed = true;
}
function processBothBars (bar1, bar2) {
return [bar1, bar2].filter(function (bar) {
return bar.processed;
}).map(function (bar) {
return bar.name;
});
}
Promise.prototype.spread = function (fn) {
return this.then(function (arr) {
return fn.apply(this, arr);
});
};
// end mock
var getFoo = function (fail) {
var promises = [];
promises.push(getBar1().then(function (bar1) {
processBar1(bar1);
if (fail) {
throw 'getBar1 Failed!';
}
return bar1;
}));
promises.push(getBar2().then(function (bar2) {
processBar2(bar2);
return bar2;
}));
return Promise.all(promises).spread(function (bar1, bar2) {
var result = processBothBars(bar1, bar2);
return result;
});
}
getFoo().then(function (result) {
console.log(result); // ['bar1', 'bar2']
});
getFoo(true).then(function (result) {
console.log(result); // doesn't happen
}).catch(function (e) {
console.error(e); // Error: getBar1 Failed!
});
.then
returns 一个承诺,所以没有必要创建一个新的包装它,除非你想防止错误到达外部承诺。
无需在这里创建您自己的任何承诺,因为 getBar1()
和 getBar2()
都已经 return 承诺 - 至少我们假设是这样,因为两者都是可行的。
提供processBar1
和processBar2
每个return你感兴趣的结果,代码将简化如下:
var getFoo = function() {
// write promises as an array literal
var promises = [
getBar1().then(processBar1),//result returned by getBar1() is automatically passed to processBar1
getBar2().then(processBar2) // ... ditto ...
];
return Promise.all(promises).spread(processBothBars);
};
Fwiw bluebird 证明了这一点:
getFoo = function() {
return Promise.join(getBar1().tap(processBar1),
getBar2().tap(processBar2),
processBothBars);
}