意外的延迟对象的行为
Unexpected deferred object's behaviour
任何人都可以澄清一下下面的代码有什么问题吗(已经阅读了很多文档和示例,但仍然不知道发生了什么)
function t() {
var d = $.Deferred();
setTimeout(function(){
d.resolve();
}, 5000);
return d.promise();
}
function test() {
var dd = $.Deferred();
$.ajax("/echo/json/").done(function() {
dd = t();
dd.done(function() { alert(" dd.done inside ajax")});
});
dd.done(function() { alert(" dd.done outside ajax")});
}
test();
输出是(在 ~ 5 秒内):
"dd.done inside ajax:"
为什么第二个 .done 不起作用?
因为那个延迟的对象没有被解析。您正在创建 2 个延迟对象并解析其中一个。
我们来看看test()
:
function test() {
var dd = $.Deferred();
$.ajax("/echo/json/").done(function() {
dd = t();
dd.done(function() { alert(" dd.done inside ajax")});
});
dd.done(function() { alert(" dd.done outside ajax")});
}
test();
局部变量dd
被初始化为一个新的jQuery延迟对象。然后,启动一个 ajax 操作,并给出一个 "done" 回调,它将调用另一个测试函数 t()
.
$.ajax()
调用基本上会立即 return,远早于它的 .done()
回调 运行。紧接着,另一个 .done()
回调为在函数开始时创建的 Deferred 实例建立。
现在,当 ajax "done" 回调 运行 时, dd
的值——最初创建的 Deferred 对象——将是 用 return 来自 t()
的 Promise 覆盖。最终 .done()
回调将是 运行,但没有任何东西解析第一个 Deferred 实例,因此 "outside" 回调永远不会发生。
您的第二个警报从未被调用,因为您分配给变量 dd
的原始延迟从未被解析,因此它的 .done()
处理程序从未被调用。
您在此处创建一个延迟并将其分配给 dd
:
var dd = $.Deferred();
然后,您设置了一个 .done()
处理程序:
dd.done(function() { alert(" dd.done outside ajax")});
但是,当您的 ajax 函数完成时,您可以使用以下行将不同的承诺分配给变量 dd
:
dd = t();
并且,因此没有任何东西解决原始承诺,因此它的 .done()
处理程序永远不会被调用。
我建议改用这种设计:
function t() {
var d = $.Deferred();
setTimeout(function(){
d.resolve();
}, 5000);
return d.promise();
}
function test() {
return $.ajax("/echo/json/").then(function() {
console.log("ajax call done");
return t();
}).then(function() {
console.log("after timer");
});
}
test().then(function() {
console.log("everything done");
});
工作演示:http://jsfiddle.net/jfriend00/atafc5hj/
这说明了以下有用的概念:
- 使用已经从
$.ajax()
返回的承诺,而不是创建自己的承诺。
- 将另一个 activity 链接到该承诺。
- 从
.then()
处理程序返回另一个承诺,使序列也等待该承诺。
- 正在从 main 函数返回链式承诺,这样您就可以看到一切何时完成。
任何人都可以澄清一下下面的代码有什么问题吗(已经阅读了很多文档和示例,但仍然不知道发生了什么)
function t() {
var d = $.Deferred();
setTimeout(function(){
d.resolve();
}, 5000);
return d.promise();
}
function test() {
var dd = $.Deferred();
$.ajax("/echo/json/").done(function() {
dd = t();
dd.done(function() { alert(" dd.done inside ajax")});
});
dd.done(function() { alert(" dd.done outside ajax")});
}
test();
输出是(在 ~ 5 秒内):
"dd.done inside ajax:"
为什么第二个 .done 不起作用?
因为那个延迟的对象没有被解析。您正在创建 2 个延迟对象并解析其中一个。
我们来看看test()
:
function test() {
var dd = $.Deferred();
$.ajax("/echo/json/").done(function() {
dd = t();
dd.done(function() { alert(" dd.done inside ajax")});
});
dd.done(function() { alert(" dd.done outside ajax")});
}
test();
局部变量dd
被初始化为一个新的jQuery延迟对象。然后,启动一个 ajax 操作,并给出一个 "done" 回调,它将调用另一个测试函数 t()
.
$.ajax()
调用基本上会立即 return,远早于它的 .done()
回调 运行。紧接着,另一个 .done()
回调为在函数开始时创建的 Deferred 实例建立。
现在,当 ajax "done" 回调 运行 时, dd
的值——最初创建的 Deferred 对象——将是 用 return 来自 t()
的 Promise 覆盖。最终 .done()
回调将是 运行,但没有任何东西解析第一个 Deferred 实例,因此 "outside" 回调永远不会发生。
您的第二个警报从未被调用,因为您分配给变量 dd
的原始延迟从未被解析,因此它的 .done()
处理程序从未被调用。
您在此处创建一个延迟并将其分配给 dd
:
var dd = $.Deferred();
然后,您设置了一个 .done()
处理程序:
dd.done(function() { alert(" dd.done outside ajax")});
但是,当您的 ajax 函数完成时,您可以使用以下行将不同的承诺分配给变量 dd
:
dd = t();
并且,因此没有任何东西解决原始承诺,因此它的 .done()
处理程序永远不会被调用。
我建议改用这种设计:
function t() {
var d = $.Deferred();
setTimeout(function(){
d.resolve();
}, 5000);
return d.promise();
}
function test() {
return $.ajax("/echo/json/").then(function() {
console.log("ajax call done");
return t();
}).then(function() {
console.log("after timer");
});
}
test().then(function() {
console.log("everything done");
});
工作演示:http://jsfiddle.net/jfriend00/atafc5hj/
这说明了以下有用的概念:
- 使用已经从
$.ajax()
返回的承诺,而不是创建自己的承诺。 - 将另一个 activity 链接到该承诺。
- 从
.then()
处理程序返回另一个承诺,使序列也等待该承诺。 - 正在从 main 函数返回链式承诺,这样您就可以看到一切何时完成。