Javascript 被束缚的承诺不会被拒绝
我很难理解为什么拒绝不会通过承诺链传递,我希望有人能帮助我理解为什么。对我来说,将功能附加到承诺链意味着我依赖于原始承诺来实现的意图。这很难解释,所以让我先展示一个问题的代码示例。(注意:本例使用的是Node和deferred Node模块。我用Dojo 1.8.3进行了测试,得到了相同的结果) 运行此操作的结果是以下输出:Javascript 被束缚的承诺不会被拒绝,javascript,node.js,dojo,promise,deferred,Javascript,Node.js,Dojo,Promise,Deferred,我很难理解为什么拒绝不会通过承诺链传递,我希望有人能帮助我理解为什么。对我来说,将功能附加到承诺链意味着我依赖于原始承诺来实现的意图。这很难解释,所以让我先展示一个问题的代码示例。(注意:本例使用的是Node和deferred Node模块。我用Dojo 1.8.3进行了测试,得到了相同的结果) 运行此操作的结果是以下输出: promise1 rejected promise2 resolved promise3 resolved 好吧,对我来说,这个结果没有意义。通过附加到该承诺链,每个承诺
promise1 rejected
promise2 resolved
promise3 resolved
好吧,对我来说,这个结果没有意义。通过附加到该承诺链,每个承诺链都意味着其将取决于d1的成功解决以及沿着该承诺链传递的结果。如果promise1中的承诺没有收到wins值,而是在其错误处理程序中获得了err值,那么链中的下一个承诺如何能够调用其success函数?它无法将有意义的值传递给下一个承诺,因为它本身没有得到值
我可以用另一种方式来描述我的想法:有三个人,约翰、金吉尔和鲍勃。约翰拥有一家小工具店。金吉尔走进他的商店,要了一袋各色的小玩意儿。他没有存货,所以他向分销商发出请求,要求将货物运给他。与此同时,他给了金吉尔一张改天支票,说他欠她一袋小玩意儿。Bob发现Ginger正在获取这些小部件,并要求他在Ginger处理完这些小部件后获取蓝色小部件。她同意了,并给了他一张便条,说明她会的。现在,John的经销商在他们的供应中找不到任何小部件,制造商也不再生产,所以他们通知John,而John又通知Ginger她无法获得这些小部件。Bob怎么能从Ginger那里得到一个蓝色的小部件,而她自己却没有
我对这个问题的第三个更现实的观点是。假设我有两个值要更新到数据库。其中一个依赖于另一个的id,但在我将其插入数据库并获得结果之前,我无法获取id。最重要的是,第一次插入依赖于来自数据库的查询。数据库调用返回承诺,我使用它将两个调用链接成一个序列
var promise = db.query({parent_id: value});
promise.then(function(query_result) {
var first_value = {
parent_id: query_result[0].parent_id
}
var promise = db.put(first_value);
promise.then(function(first_value_result) {
var second_value = {
reference_to_first_value_id: first_value_result.id
}
var promise = db.put(second_value);
promise.then(function(second_value_result) {
values_successfully_entered();
}, function(err) { return err });
}, function(err) { return err });
}, function(err) { return err });
现在,在这种情况下,如果db.query失败,它将调用第一个的err函数。但接下来它将称为下一个承诺的成功函数。虽然该承诺期望第一个值的结果,但它将从其错误处理函数中获取错误消息
所以,我的问题是,如果我必须测试成功函数中的错误,为什么我会有一个错误处理函数
抱歉这么长时间。我只是不知道如何用另一种方式来解释
更新和更正
(注意:我删除了我曾经对某些评论所做的回复。因此,如果有人对我的回复发表评论,他们的评论在我删除后可能会显得断章取义。很抱歉,我会尽量简短。)
谢谢大家的回复。我想首先向大家道歉,因为我的问题写得如此糟糕,尤其是我的伪代码。我有点太过激进了,试图保持简短
多亏了Bergi的回答,我想我在逻辑上找到了错误。我想我可能忽略了另一个导致我的问题的问题。这可能导致承诺链的工作方式与我认为的不同。我仍然在测试代码的不同元素,所以我甚至不能形成一个适当的问题来看看我做错了什么。尽管如此,我还是想告诉你最新情况,谢谢你的帮助
对我来说,这个结果毫无意义。通过附加到该承诺链,每个承诺链都意味着其将取决于d1的成功解决以及沿着该承诺链传递的结果
不。您描述的不是一个链,而是将所有回调附加到d1
。但是,如果您想将某个内容链接到then
,那么promise2
的结果取决于promise1
的分辨率以及then
回调如何处理它
文件规定:
返回回调结果的新承诺
.then
方法通常是根据(或更严格的)标准来看待的。这意味着回调外壳返回承诺将被同化为promise2
的解析,如果没有成功/错误处理程序,相应的结果将直接传递给promise2
——因此您可以简单地忽略处理程序来传播错误
但是,如果处理了错误,则生成的promise2
被视为是固定的,并将使用该值来实现。如果您不想这样做,您必须重新抛出错误,就像在try-catch子句中一样。或者,您可以从处理程序返回一个(被拒绝的)承诺。不确定拒绝的Dojo方式是什么,但是:
var d1 = d();
var promise1 = d1.promise.then(
function(wins) { console.log('promise1 resolved'); return wins;},
function(err) { console.log('promise1 rejected'); throw err;});
var promise2 = promise1.then(
function(wins) { console.log('promise2 resolved'); return wins;},
function(err) { console.log('promise2 rejected'); throw err;});
var promise3 = promise2.then(
function(wins) { console.log('promise3 resolved'); return wins;},
function(err) { console.log('promise3 rejected'); throw err;});
d1.reject(new Error());
Bob怎么能从Ginger那里得到一个蓝色的小部件,而她自己却没有
他不应该这样做。如果没有错误处理程序,他只会感知到来自Ginger的消息((来自分发服务器)来自John)没有小部件了。然而,如果Ginger为这种情况设置了一个错误处理程序,她仍然可以兑现她的承诺,如果John或他的经销商没有留下蓝色的,她可以从自己的小屋给Bob一个绿色的小部件
要将错误回调转换为metapher,处理程序返回的return err
就像说“如果没有剩下小部件,只需告诉他没有剩下小部件-它与所需的小部件一样好”
在数据库情况下,如果
var d1 = d();
var promise1 = d1.promise.then(
function(wins) { console.log('promise1 resolved'); return wins;},
function(err) { console.log('promise1 rejected'); throw err;});
var promise2 = promise1.then(
function(wins) { console.log('promise2 resolved'); return wins;},
function(err) { console.log('promise2 rejected'); throw err;});
var promise3 = promise2.then(
function(wins) { console.log('promise3 resolved'); return wins;},
function(err) { console.log('promise3 rejected'); throw err;});
d1.reject(new Error());
var promise = db.query({parent_id: value});
promise.then(function(query_result) {
var first_value = {
parent_id: query_result[0].parent_id
}
var promise = db.put(first_value);
return promise.then(function(first_value_result) {
var second_value = {
reference_to_first_value_id: first_value_result.id
}
var promise = db.put(second_value);
return promise.then(function(second_value_result) {
return values_successfully_entered();
});
});
});
db.query({parent_id: value}).then(function(query_result) {
return db.put({
parent_id: query_result[0].parent_id
});
}).then(function(first_value_result) {
return db.put({
reference_to_first_value_id: first_value_result.id
});
}.then(values_successfully_entered);
promise1 rejected
promise2 rejected
promise3 rejected
promise.then(function(first_value) {
console.log('promise1 resolved');
var promise = db.put(first_value);
promise.then(function (second_value) {
console.log('promise2 resolved');
var promise = db.put(second_value);
promise.then(
function (wins) { console.log('promise3 resolved'); },
function (err) { console.log('promise3 rejected'); return err; });
}, function (err) { console.log('promise2 rejected'); return err;});
}, function (err) { console.log('promise1 rejected'); return err});
promise1 rejected
function (err) { console.log('promise1 rejected'); throw err; });
class TraceError extends Error {
constructor(message, ...causes) {
super(message);
const stack = Object.getOwnPropertyDescriptor(this, 'stack');
Object.defineProperty(this, 'stack', {
get: () => {
const stacktrace = stack.get.call(this);
let causeStacktrace = '';
for (const cause of causes) {
if (cause.sourceStack) { // trigger lookup
causeStacktrace += `\n${cause.sourceStack}`;
} else if (cause instanceof Error) {
causeStacktrace += `\n${cause.stack}`;
} else {
try {
const json = JSON.stringify(cause, null, 2);
causeStacktrace += `\n${json.split('\n').join('\n ')}`;
} catch (e) {
causeStacktrace += `\n${cause}`;
// ignore
}
}
}
causeStacktrace = causeStacktrace.split('\n').join('\n ');
return stacktrace + causeStacktrace;
}
});
// access first error
Object.defineProperty(this, 'cause', {value: () => causes[0], enumerable: false, writable: false});
// untested; access cause stack with error.causes()
Object.defineProperty(this, 'causes', {value: () => causes, enumerable: false, writable: false});
}
}
throw new TraceError('Could not set status', srcError, ...otherErrors);
TraceError#cause - first error
TraceError#causes - list of chained errors