我是这样的承诺,
function getMode(){
var deferred = Promise.defer();
checkIf('A')
.then(function(bool){
if(bool){
deferred.resolve('A');
}else{
return checkIf('B');
}
}).then(function(bool){
if(bool){
deferred.resolve('B');
}else{
return checkIf('C');
}
}).then(function(bool){
if(bool){
deferred.resolve('C');
}else{
deferred.reject();
}
});
return deferred.promise;
}
checkIf
会返回一个承诺,是checkIf
无法修改。
我如何在第一场比赛中脱颖而出? (除了明确抛出错误之外的任何其他方式?)
答案 0 :(得分:3)
我会使用coroutines/spawns,这会导致更多更简单的代码:
function* getMode(){
if(yield checkIf('A'))
return 'A';
if(yield checkIf('B'))
return 'B';
if(yield checkIf('C'))
return 'C';
throw undefined; // don't actually throw or reject with non `Error`s in production
}
如果你没有发电机,那么它总是跟踪或6to5。
答案 1 :(得分:3)
我想你不想要链条。以同步的方式,你已经写了
function getMode(){
if (checkIf('A')) {
return 'A';
} else {
if (checkIf('B')) {
return 'B';
} else {
if (checkIf('C')) {
return 'C';
} else {
throw new Error();
}
}
}
}
这就是它应该如何转化为承诺:
function getMode(){
checkIf('A').then(function(bool) {
if (bool)
return 'A';
return checkIf('B').then(function(bool) {
if (bool)
return 'B';
return checkIf('C').then(function(bool) {
if (bool)
return 'C';
throw new Error();
});
});
});
}
承诺中没有if else
- 扁平化。
答案 2 :(得分:3)
你可以使用
return { then: function() {} };
.then(function(bool){
if(bool){
deferred.resolve('A');
return { then: function() {} }; // end/break the chain
}else{
return checkIf('B');
}
})
return语句返回一个" then-able",只是then方法什么都不做。 当从then()函数返回时,then()将尝试从thenable中获取结果。 当时能够"然后"接受回调但在这种情况下永远不会被调用。所以"然后()"返回,并且链的其余部分的回调不会发生。
答案 3 :(得分:1)
您可以创建一个firstSucceeding
函数,该函数将返回第一个成功操作的值或抛出NonSucceedingError
。
我已经使用过ES6承诺,但您可以调整算法以支持您选择的承诺界面。
function checkIf(val) {
console.log('checkIf called with', val);
return new Promise(function (resolve, reject) {
setTimeout(resolve.bind(null, [val, val === 'B']), 0);
});
}
var firstSucceeding = (function () {
return function (alternatives, succeeded) {
var failedPromise = Promise.reject(NoneSucceededError());
return (alternatives || []).reduce(function (promise, alternative) {
return promise.then(function (result) {
if (succeeded(result)) return result;
else return alternative();
}, alternative);
}, failedPromise).then(function (result) {
if (!succeeded(result)) throw NoneSucceededError();
return result;
});
}
function NoneSucceededError() {
var error = new Error('None succeeded');
error.name = 'NoneSucceededError';
return error;
}
})();
function getMode() {
return firstSucceeding([
checkIf.bind(null, 'A'),
checkIf.bind(null, 'B'),
checkIf.bind(null, 'C')
], function (result) {
return result[1] === true;
});
}
getMode().then(function (result) {
console.log('res', result);
}, function (err) { console.log('err', err); });

答案 4 :(得分:0)
我喜欢到目前为止发布的很多答案,可以缓解q readme所谓的“厄运金字塔”。为了便于讨论,我将添加我在搜索周围以查看其他人正在做什么之前插入的模式。我写了一个像
这样的函数var null_wrap = function (fn) {
return function () {
var i;
for (i = 0; i < arguments.length; i += 1) {
if (arguments[i] === null) {
return null;
}
}
return fn.apply(null, arguments);
};
};
我做了一些与@ vilicvane的答案完全类似的事情,除了throw new BreakSignal()
之外,我写了return null
,并将所有后续的.then
回调包裹在null_wrap
中
then(null_wrap(function (res) { /* do things */ }))
我认为这是一个很好的答案b / c它避免了很多缩进和b / c OP特别要求的解决方案不是throw
。那说,我可以回去使用更像@vilicvane做的事情b / c一些图书馆的承诺可能会返回null
来表示除了“打破链条”以外的东西,这可能会令人困惑。
这更像是要求获得更多评论/答案,而不是“这绝对是做到这一点的方式”。
答案 5 :(得分:0)
可能会来晚会,但我最近发布了一个使用生成器和co
库来回答这个问题的答案(见解决方案2):
代码如下:
const requestHandler = function*() {
const survey = yield Survey.findOne({
_id: "bananasId"
});
if (survey !== null) {
console.log("use HTTP PUT instead!");
return;
}
try {
//saving empty object for demonstration purposes
yield(new Survey({}).save());
console.log("Saved Successfully !");
return;
}
catch (error) {
console.log(`Failed to save with error: ${error}`);
return;
}
};
co(requestHandler)
.then(() => {
console.log("finished!");
})
.catch(console.log);
您几乎可以编写实际上异步的同步代码!
希望它有所帮助!
答案 6 :(得分:0)
尝试使用像这样的库:
https://www.npmjs.com/package/promise-chain-break
db.getData()
.then(pb((data) => {
if (!data.someCheck()) {
tellSomeone();
// All other '.then' calls will be skiped
return pb.BREAK;
}
}))
.then(pb(() => {
}))
.then(pb(() => {
}))
.catch((error) => {
console.error(error);
});