如何打破承诺链
how to break promise chain
我以这样的方式承诺,
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
returns一个承诺,是checkIf
不可修改.
如何在第一场比赛中摆脱束缚? (除了显式抛出错误之外还有什么方法吗?)
您可以创建一个 firstSucceeding
函数,它将 return 第一个成功操作的值或抛出 NonSucceedingError
.
我使用过 ES6 promises,但您可以调整算法以支持您选择的 promise 接口。
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); });
我只想使用 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
}
如果您没有发电机,那么总是有 traceur 或 6to5。
我想你不想要这里的连锁店。以同步方式,你会写
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
-扁平化。
Any way other than explicitly throwing error?
您可能需要抛出一些东西,但不一定是错误。
大多数 promise 实现都有方法 catch
接受第一个参数作为错误类型(但不是全部,也不是 ES6 promise),这在这种情况下会很有帮助:
function BreakSignal() { }
getPromise()
.then(function () {
throw new BreakSignal();
})
.then(function () {
// Something to skip.
})
.catch(BreakSignal, function () { })
.then(function () {
// Continue with other works.
});
我在我自己的 promise 库的最近实现中添加了中断功能。如果你使用 ThenFail(你可能不会),你可以这样写:
getPromise()
.then(function () {
Promise.break;
})
.then(function () {
// Something to skip.
})
.enclose()
.then(function () {
// Continue with other works.
});
我喜欢到目前为止发布的很多答案,这些答案减轻了 q readme 所谓的 "pyramid of doom"。为了便于讨论,我将添加我在四处搜索以查看其他人在做什么之前找出的模式。我写了一个像
这样的函数
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 一些图书馆的承诺可能 return null
来指示 "break the chain" 以外的东西,那可能是令人困惑。
与 "this is definitely the way to do it" 答案相比,这更像是对 comments/answers 的呼吁。
可能来晚了,但我最近发布了一个使用生成器和 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);
您几乎可以编写实际上是异步的同步代码!
希望对您有所帮助!
你可以使用
return { then: function() {} };
.then(function(bool){
if(bool){
deferred.resolve('A');
return { then: function() {} }; // end/break the chain
}else{
return checkIf('B');
}
})
return 语句 return 是一个 "then-able",只是 then 方法什么都不做。
当从 then() 中的函数 returned 时, then() 将尝试从 thenable 中获取结果。
then-able 的 "then" 接受回调,但在这种情况下永远不会调用。所以 "then()" returns,以及链的其余部分的回调不会发生。
尝试使用像这样的库:
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);
});
我以这样的方式承诺,
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
returns一个承诺,是checkIf
不可修改.
如何在第一场比赛中摆脱束缚? (除了显式抛出错误之外还有什么方法吗?)
您可以创建一个 firstSucceeding
函数,它将 return 第一个成功操作的值或抛出 NonSucceedingError
.
我使用过 ES6 promises,但您可以调整算法以支持您选择的 promise 接口。
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); });
我只想使用 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
}
如果您没有发电机,那么总是有 traceur 或 6to5。
我想你不想要这里的连锁店。以同步方式,你会写
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
-扁平化。
Any way other than explicitly throwing error?
您可能需要抛出一些东西,但不一定是错误。
大多数 promise 实现都有方法 catch
接受第一个参数作为错误类型(但不是全部,也不是 ES6 promise),这在这种情况下会很有帮助:
function BreakSignal() { }
getPromise()
.then(function () {
throw new BreakSignal();
})
.then(function () {
// Something to skip.
})
.catch(BreakSignal, function () { })
.then(function () {
// Continue with other works.
});
我在我自己的 promise 库的最近实现中添加了中断功能。如果你使用 ThenFail(你可能不会),你可以这样写:
getPromise()
.then(function () {
Promise.break;
})
.then(function () {
// Something to skip.
})
.enclose()
.then(function () {
// Continue with other works.
});
我喜欢到目前为止发布的很多答案,这些答案减轻了 q readme 所谓的 "pyramid of doom"。为了便于讨论,我将添加我在四处搜索以查看其他人在做什么之前找出的模式。我写了一个像
这样的函数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 一些图书馆的承诺可能 return null
来指示 "break the chain" 以外的东西,那可能是令人困惑。
与 "this is definitely the way to do it" 答案相比,这更像是对 comments/answers 的呼吁。
可能来晚了,但我最近发布了一个使用生成器和 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);
您几乎可以编写实际上是异步的同步代码!
希望对您有所帮助!
你可以使用
return { then: function() {} };
.then(function(bool){
if(bool){
deferred.resolve('A');
return { then: function() {} }; // end/break the chain
}else{
return checkIf('B');
}
})
return 语句 return 是一个 "then-able",只是 then 方法什么都不做。 当从 then() 中的函数 returned 时, then() 将尝试从 thenable 中获取结果。 then-able 的 "then" 接受回调,但在这种情况下永远不会调用。所以 "then()" returns,以及链的其余部分的回调不会发生。
尝试使用像这样的库:
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);
});