如何将延迟对象应用于大块代码?
How to apply a deferred object to a large block of code?
尽管这里有很多关于该主题的答案,但我仍然没有真正理解 $.Deferred()
对象。
我想更好地理解它们并避免任何 "anti-patterns"。
我已阅读:
https://api.jquery.com/category/deferred-object/
而"sticks"的是,它是一个对象,它有可用的方法,例如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()
它在异步代码块之后。
- Return一个
promise()
在异步代码块之后。
- 调用
done()
方法。
上面的示例似乎按预期工作,但是当我尝试将此逻辑应用于包含 $.ajax()
请求的大型函数时,以便将 class 应用于它之后的内容已加载,class 未被应用。
我可以通过 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()
问题的一个很好、简短、简单的回答,我理解它的逻辑,但似乎不适用于我的场景(例如,我不能只是链接简单的fadeOut()
之后的promise()
):
问题
在上面的大型函数示例中,在 ajax 请求等完成执行后调用 done()
需要遵循什么约定?
首先,我建议更改此设置:
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 promise 标准与 new Promise()
的工作方式,因此将您的编程朝着标准的方向发展通常是个好主意.
使用 .then()
而不是 .done()
。同样,.then()
是 ES6 promise 标准的工作方式,jQuery 很好地支持它。如果在未来的某个时候,您将 function1()
更改为使用实际的 ES6 promise 而不是 jQuery promise,那么您的 function1().then()
将继续正常工作。
在 jQuery 中,一个 Ajax 请求已经 return 是一个承诺。没有必要将它包装在 deferred 中,事实上,这样做是一种反模式(在不需要创建新承诺时创建承诺)。
Promises 没有魔力,只知道异步事情何时完成。相反,一些代码必须在异步操作完成时专门调用 .resolve()
。而且,在 jQuery Ajax 函数的情况下,这是自动为您完成的,并承诺任何 jQuery Ajax 函数 return。所以,你可以这样做:
function largeFunction(myVar) {
return $.ajax(...);
}
largeFunction(....).then(function(results) {
// handle successful results here
}, function(jqXHR, textStatus, errorThrown ) {
// handle error here
});
如果你在 largeFunction()
中有多个 Ajax 函数或异步操作,那么你可以使用 promises 链接它们(这将对它们进行排序)或协调它们并且仍然 return单一的承诺,代表一切何时完成并代表期望的最终结果。 jQuery 提供协调工具,例如 $.when()
以了解何时完成多个承诺(这是 ES6 标准中的 Promise.all()
)。
尽管这里有很多关于该主题的答案,但我仍然没有真正理解 $.Deferred()
对象。
我想更好地理解它们并避免任何 "anti-patterns"。
我已阅读:
https://api.jquery.com/category/deferred-object/
而"sticks"的是,它是一个对象,它有可用的方法,例如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()
它在异步代码块之后。- Return一个
promise()
在异步代码块之后。 - 调用
done()
方法。
上面的示例似乎按预期工作,但是当我尝试将此逻辑应用于包含 $.ajax()
请求的大型函数时,以便将 class 应用于它之后的内容已加载,class 未被应用。
我可以通过 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()
问题的一个很好、简短、简单的回答,我理解它的逻辑,但似乎不适用于我的场景(例如,我不能只是链接简单的fadeOut()
之后的promise()
):
问题
在上面的大型函数示例中,在 ajax 请求等完成执行后调用 done()
需要遵循什么约定?
首先,我建议更改此设置:
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 promise 标准与new Promise()
的工作方式,因此将您的编程朝着标准的方向发展通常是个好主意.使用
.then()
而不是.done()
。同样,.then()
是 ES6 promise 标准的工作方式,jQuery 很好地支持它。如果在未来的某个时候,您将function1()
更改为使用实际的 ES6 promise 而不是 jQuery promise,那么您的function1().then()
将继续正常工作。
在 jQuery 中,一个 Ajax 请求已经 return 是一个承诺。没有必要将它包装在 deferred 中,事实上,这样做是一种反模式(在不需要创建新承诺时创建承诺)。
Promises 没有魔力,只知道异步事情何时完成。相反,一些代码必须在异步操作完成时专门调用 .resolve()
。而且,在 jQuery Ajax 函数的情况下,这是自动为您完成的,并承诺任何 jQuery Ajax 函数 return。所以,你可以这样做:
function largeFunction(myVar) {
return $.ajax(...);
}
largeFunction(....).then(function(results) {
// handle successful results here
}, function(jqXHR, textStatus, errorThrown ) {
// handle error here
});
如果你在 largeFunction()
中有多个 Ajax 函数或异步操作,那么你可以使用 promises 链接它们(这将对它们进行排序)或协调它们并且仍然 return单一的承诺,代表一切何时完成并代表期望的最终结果。 jQuery 提供协调工具,例如 $.when()
以了解何时完成多个承诺(这是 ES6 标准中的 Promise.all()
)。