尽管这个主题有很多答案,但我仍然不太了解$.Deferred()
个对象。
我希望更好地理解它们并避免任何“反模式”。
我读过:
https://api.jquery.com/category/deferred-object/
“坚持”的是它是一个有可用方法的对象,例如done()
。
我试图根据this answer创建最简单的示例:
function function1() {
// create a deferred object first
var dfrd1 = $.Deferred();
// mimic an async request
setTimeout(function() {
// lots of async stuff here
// resolve the deferred object
dfrd1.resolve();
}, 1000);
// return a promise()
return dfrd1.promise();
}
function1().done(function() {
// when function1 is done, do something
console.log('function1 is done!');
});
这似乎有四个组成部分:
$.Deferred()
对象。resolve()
在异步代码块之后。promise()
。done()
方法。上面的示例似乎按预期工作,但是当我尝试将此逻辑应用于包含$.ajax()
请求的大型函数时,为了在加载后将类应用于内容,该类是没有被应用。
我可以通过firebug运行addClass()
代码,因此该代码没有任何问题。
大函数场景的伪代码是:
function largeFunction(myVar) {
// create a deferred object first
var dfrd1 = $.Deferred();
// lots of code and an ajax request here
// resolve the object and return a promise
// (this seems naive to hope resolve will
// know when everything above has completed)
dfrd1.resolve();
return dfrd1.promise();
}
// call the done() method from an on click event
$(document).on("click", ".some_class", function() {
largeFunction(myVar).done(function() {
console.log('largeFunction(myVar) is done, you can now add class');
var my_classes = $(".my_class");
$.each(classes, function(index, value) {
$(this).addClass("another_class");
});
});
});
以下是对$.Deferred()
问题的一个好的,简短的答案,我理解其中的逻辑,但似乎并不适用于我的场景(例如,我不能只链接promise()
简单fadeOut()
)后的{1}}:
https://stackoverflow.com/a/24234881/1063287
问题
在上面的大函数示例中,为了在ajax请求等完成执行后调用done()
,我需要遵循哪些约定?
答案 0 :(得分:1)
首先,我建议改变这个:
function function1() {
// create a deferred object first
var dfrd1 = $.Deferred();
// mimic an async request
setTimeout(function() {
// lots of async stuff here
// resolve the deferred object
dfrd1.resolve();
}, 1000);
// return a promise()
return dfrd1.promise();
}
function1().done(function() {
// when function1 is done, do something
console.log('function1 is done!');
});
到此:
function function1() {
// create a deferred object first
return $.Deferred(function(def) {
// mimic an async request
setTimeout(function() {
// lots of async stuff here
// resolve the deferred object
def.resolve();
}, 1000);
}).promise();
}
function1().then(function() {
// when function1 is done, do something
console.log('function1 is done!');
});
您的原始代码工作正常且不包含反模式,但这个新代码具有以下优点:
使用$.Deferred()
的回调更接近ES6承诺标准如何与new Promise()
一起使用,因此将编程转向标准方向通常是个好主意
使用.then()
代替.done()
。同样,.then()
是ES6承诺标准的工作原理,jQuery支持它就好了。如果在将来的某个时候,您更改function1()
以使用实际的ES6承诺而不是jQuery承诺,那么您的function1().then()
将继续正常工作。
在jQuery中,Ajax请求已经返回一个promise。没有必要将它包装成延迟,事实上,这样做是一种反模式(当你不需要创建一个新模式时创建一个承诺)。
Promise没有神奇的力量可以知道异步事情何时完成。相反,某些代码必须在异步操作完成时专门调用.resolve()
。而且,在jQuery Ajax函数的情况下,这是自动完成的,承诺任何jQuery Ajax函数返回。所以,你可以这样做:
function largeFunction(myVar) {
return $.ajax(...);
}
largeFunction(....).then(function(results) {
// handle successful results here
}, function(jqXHR, textStatus, errorThrown ) {
// handle error here
});
如果在largeFunction()
中有多个Ajax函数或异步操作,那么你可以使用promises来链接它们(它们将对它们进行排序)或协调它们,并仍然返回一个代表何时完成所有代表的单个promise期望的最终结果。 jQuery提供了诸如$.when()
之类的协调工具,以便知道何时完成了多个promise(这是ES6标准中的Promise.all()
)。