ES6 承诺,仅当先前的承诺被拒绝时才链接承诺,同时保留拒绝原因
ES6 promises, chaining promises only if previous promises were rejected, while keeping rejection reasons
我正在构建一个身份验证 API,尝试根据不同的身份验证方法进行身份验证,直到成功(例如 Spring 安全)。
每个身份验证方法returns一个承诺,如果身份验证成功则履行,如果身份验证失败则拒绝。
要尝试对用户进行身份验证,我需要按顺序调用身份验证方法:
- 如果第一种身份验证方法成功,则用户通过身份验证,我
不希望调用其他身份验证方法。
- 如果第一种认证方式失败,我需要尝试第二种认证方式。等等...
- 如果none种认证方法成功,我需要拒绝认证,也许
了解每次身份验证失败的原因。
- 如果身份验证成功,我需要取回一个值(身份验证对象)。
这个过程几乎就是库调用 .any(或 .some)的过程,只是我不想每次都执行承诺(因此尝试每一种身份验证方法,这会导致不必要的工作量)。 只有在上一个验证方法失败时我才想尝试下一个验证方法。
问题 1:Promise/A+ 兼容的库中是否有可用的函数?
问题2:我一直在想下面的方法(参考下面的代码),有没有更好的方法?
// Defining some promise factories
var promiseFactory1 = {
buildPromise: function() {
return new Promise((resolve, reject) => {
console.log('trying p1...');
// resolve('p1 success');
reject('p1 failure');
})
}
};
var promiseFactory2 = {
buildPromise: function() {
return new Promise((resolve, reject) => {
console.log('trying p2...');
// resolve('p2 success');
reject('p2 failure');
})
}
};
var promiseFactory3 = {
buildPromise: function() {
return new Promise((resolve, reject) => {
console.log('trying p3...');
resolve('p3 success');
// reject('p3 failure');
})
}
};
// Building the promise
let promisesFactory = [promiseFactory1, promiseFactory2, promiseFactory3];
let rejections = [];
var reducedPromise = promisesFactory.reduce(function(promise, nextFactory) {
if (promise === null) return nextFactory.buildPromise();
return promise.catch(err => {
rejections.push(err);
return nextFactory.buildPromise();
});
}, null);
reducedPromise
.catch(err => {
rejections.push(err); // catching the last rejection
})
.then(success => {
if(rejections.length == promisesFactory.length) {
console.log(rejections);
// TODO return Promise.reject(new SomeCustomError());
} else {
console.log(success);
// TODO return Promise.resolve(success);
}
});
我相信你可以这样做(其中 auth1
、auth2
和 auth3
是授权函数 returning 承诺):
auth1(/*args*/)
.catch(failed => auth2(/*args*/))
.catch(failed => auth3(/*args*/))
.then(result => {
console.log("Success:" + result);
return result;
})
.catch(failed => {
console.log("Failure:" + failed);
});
因为我们没有 then
回调,分辨率值会传播到最终的 then
(就像有 .then(result => result)
);但我们 return 来自 catch
回调的新承诺,触发下一个身份验证方法。
最后的then
获取第一个成功的auth方法的解析值;上面最后的 catch
只是得到了 last 失败的身份验证方法 (auth3
).
的拒绝原因
如果您需要所有失败的原因,您可以将它们保存在一个数组中:
let failures = [];
auth1(/*args*/)
.catch(failed => {failures.push(failed); return auth2(/*args*/);})
.catch(failed => {failures.push(failed); return auth3(/*args*/);})
.then(result => {
console.log("Success: " + result + " (failed: " + failures.join(", ") + ")");
return result;
})
.catch(failed => {
failures.push(failed);
console.log("Failures: " + failures.join(", "));
});
如果您的身份验证方法本身在一个数组中,您可以循环执行上述操作:
let auths = [auth1.bind(null, /*args*/), auth2.bind(null, /*args*/), auth3.bind(null, /*args*/)];
return auths.reduce((p, auth) => p.catch(failed => auth()), Promise.reject())
.then(result => {
console.log("Success: " + result);
return result;
})
.catch(failed => {
console.log("Failed: " + failed);
});
我正在构建一个身份验证 API,尝试根据不同的身份验证方法进行身份验证,直到成功(例如 Spring 安全)。
每个身份验证方法returns一个承诺,如果身份验证成功则履行,如果身份验证失败则拒绝。
要尝试对用户进行身份验证,我需要按顺序调用身份验证方法:
- 如果第一种身份验证方法成功,则用户通过身份验证,我 不希望调用其他身份验证方法。
- 如果第一种认证方式失败,我需要尝试第二种认证方式。等等...
- 如果none种认证方法成功,我需要拒绝认证,也许 了解每次身份验证失败的原因。
- 如果身份验证成功,我需要取回一个值(身份验证对象)。
这个过程几乎就是库调用 .any(或 .some)的过程,只是我不想每次都执行承诺(因此尝试每一种身份验证方法,这会导致不必要的工作量)。 只有在上一个验证方法失败时我才想尝试下一个验证方法。
问题 1:Promise/A+ 兼容的库中是否有可用的函数? 问题2:我一直在想下面的方法(参考下面的代码),有没有更好的方法?
// Defining some promise factories
var promiseFactory1 = {
buildPromise: function() {
return new Promise((resolve, reject) => {
console.log('trying p1...');
// resolve('p1 success');
reject('p1 failure');
})
}
};
var promiseFactory2 = {
buildPromise: function() {
return new Promise((resolve, reject) => {
console.log('trying p2...');
// resolve('p2 success');
reject('p2 failure');
})
}
};
var promiseFactory3 = {
buildPromise: function() {
return new Promise((resolve, reject) => {
console.log('trying p3...');
resolve('p3 success');
// reject('p3 failure');
})
}
};
// Building the promise
let promisesFactory = [promiseFactory1, promiseFactory2, promiseFactory3];
let rejections = [];
var reducedPromise = promisesFactory.reduce(function(promise, nextFactory) {
if (promise === null) return nextFactory.buildPromise();
return promise.catch(err => {
rejections.push(err);
return nextFactory.buildPromise();
});
}, null);
reducedPromise
.catch(err => {
rejections.push(err); // catching the last rejection
})
.then(success => {
if(rejections.length == promisesFactory.length) {
console.log(rejections);
// TODO return Promise.reject(new SomeCustomError());
} else {
console.log(success);
// TODO return Promise.resolve(success);
}
});
我相信你可以这样做(其中 auth1
、auth2
和 auth3
是授权函数 returning 承诺):
auth1(/*args*/)
.catch(failed => auth2(/*args*/))
.catch(failed => auth3(/*args*/))
.then(result => {
console.log("Success:" + result);
return result;
})
.catch(failed => {
console.log("Failure:" + failed);
});
因为我们没有 then
回调,分辨率值会传播到最终的 then
(就像有 .then(result => result)
);但我们 return 来自 catch
回调的新承诺,触发下一个身份验证方法。
最后的then
获取第一个成功的auth方法的解析值;上面最后的 catch
只是得到了 last 失败的身份验证方法 (auth3
).
如果您需要所有失败的原因,您可以将它们保存在一个数组中:
let failures = [];
auth1(/*args*/)
.catch(failed => {failures.push(failed); return auth2(/*args*/);})
.catch(failed => {failures.push(failed); return auth3(/*args*/);})
.then(result => {
console.log("Success: " + result + " (failed: " + failures.join(", ") + ")");
return result;
})
.catch(failed => {
failures.push(failed);
console.log("Failures: " + failures.join(", "));
});
如果您的身份验证方法本身在一个数组中,您可以循环执行上述操作:
let auths = [auth1.bind(null, /*args*/), auth2.bind(null, /*args*/), auth3.bind(null, /*args*/)];
return auths.reduce((p, auth) => p.catch(failed => auth()), Promise.reject())
.then(result => {
console.log("Success: " + result);
return result;
})
.catch(failed => {
console.log("Failed: " + failed);
});