假设我有一组promise正在发出网络请求,其中一个将失败:
// http://does-not-exist will throw a TypeError
var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]
Promise.all(arr)
.then(res => console.log('success', res))
.catch(err => console.log('error', err)) // This is executed
假设我想要等到所有这些都完成,不管是否有一个失败了。可能有一个资源的网络错误,我可以没有,但如果我能得到,我想在继续之前。我想优雅地处理网络故障。
因为承诺。所有这些都没有留下任何空间,在不使用承诺库的情况下,处理这个问题的推荐模式是什么?
从ES5开始,我一直在使用以下代码。
Promise.wait = function(promiseQueue){
if( !Array.isArray(promiseQueue) ){
return Promise.reject('Given parameter is not an array!');
}
if( promiseQueue.length === 0 ){
return Promise.resolve([]);
}
return new Promise((resolve, reject) =>{
let _pQueue=[], _rQueue=[], _readyCount=false;
promiseQueue.forEach((_promise, idx) =>{
// Create a status info object
_rQueue.push({rejected:false, seq:idx, result:null});
_pQueue.push(Promise.resolve(_promise));
});
_pQueue.forEach((_promise, idx)=>{
let item = _rQueue[idx];
_promise.then(
(result)=>{
item.resolved = true;
item.result = result;
},
(error)=>{
item.resolved = false;
item.result = error;
}
).then(()=>{
_readyCount++;
if ( _rQueue.length === _readyCount ) {
let result = true;
_rQueue.forEach((item)=>{result=result&&item.resolved;});
(result?resolve:reject)(_rQueue);
}
});
});
});
};
用法签名就像Promise.all。主要的区别在于《承诺》。等待会等待所有的承诺来完成自己的工作。
我只是想要一个完全复制ES2020行为的填充,因为我被锁定在比12.9更早的节点版本(当Promise。allsettle出现了),不幸的是。所以不管怎样,这是我的版本:
const settle = (promise) => (promise instanceof Promise) ?
promise.then(val => ({ value: val, status: "fulfilled" }),
err => ({ reason: err, status: "rejected" })) :
{ value: promise, status: 'fulfilled' };
const allSettled = async (parr) => Promise.all(parr.map(settle));
它处理承诺值和非承诺值的混合数组,就像ES版本一样。它返回与原生版本相同的{status, value/reason}对象数组。
类似的答案,但更适合ES6:
const a = Promise.resolve(1);
const b =承诺。拒绝(新的错误(2));
const c = Promise.resolve(3);
的承诺。[a, b, c]。(p => p.catch(e => e)))
.then(results => console.log(results)) // 1,错误:2,3
.catch(e => console.log(e));
const console = {log: msg => div.innerHTML += msg + "<br>"};
< div id = " div " > < / div >
根据返回值的类型,通常可以很容易地区分错误(例如,用undefined表示“don't care”,用typeof表示普通的非对象值,用result。result.toString(). startswith ("Error:")等
更新,你可能需要使用内置的本机promise . allsettle:
Promise.allSettled([promise]).then(([result]) => {
//reach here regardless
// {status: "fulfilled", value: 33}
});
作为一个有趣的事实,下面的答案是将该方法添加到语言中的现有技术:]
当然,你只需要反思一下:
const reflect = p => p.then(v => ({v, status: "fulfilled" }),
e => ({e, status: "rejected" }));
reflect(promise).then((v) => {
console.log(v.status);
});
或者使用ES5:
function reflect(promise){
return promise.then(function(v){ return {v:v, status: "fulfilled" }},
function(e){ return {e:e, status: "rejected" }});
}
reflect(promise).then(function(v){
console.log(v.status);
});
或者在你的例子中:
var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]
Promise.all(arr.map(reflect)).then(function(results){
var success = results.filter(x => x.status === "fulfilled");
});
你可以通过同步执行器nsynjs按顺序执行你的逻辑。它将在每个承诺上暂停,等待解析/拒绝,并将解析的结果分配给data属性,或者抛出异常(用于处理您将需要try/catch块)。这里有一个例子:
function synchronousCode() {
function myFetch(url) {
try {
return window.fetch(url).data;
}
catch (e) {
return {status: 'failed:'+e};
};
};
var arr=[
myFetch("https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"),
myFetch("https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/NONEXISTANT.js"),
myFetch("https://ajax.NONEXISTANT123.com/ajax/libs/jquery/2.0.0/NONEXISTANT.js")
];
console.log('array is ready:',arr[0].status,arr[1].status,arr[2].status);
};
nsynjs.run(synchronousCode,{},function(){
console.log('done');
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>