Deferred and Promise
ES6 and JQuery have deffered and Promise, but they are slightly different. But their role can be easily described in two words.
- Deffered Trigger Resolve or Reject
- What to do after resolve or reject is declared in Promise (callback)
In JQuery
var deferred = $.Deferred();var promise = deferred.promise();
In the ES6
var deferred = Promise.defer();var promise= defered.promise;
The MDN declares that Deferred was declared expired in Gecko 30 and should not be used, but instead new Promise()
. About new Promise()
will be explained later.
The deferred/promise of JQuery
The most commonly used Promise objects in JQuery are $.ajax()
returned, and the most common methods are not then
, but done
, fail
and always
. Besides $.ajax()
, JQuery also provides $.get()
, $.post()
and $.getJSON()
so simplify Ajax calls, which return the $.ajax()
same return value as a Promise object.
$.ajax()
a Jqxhr object is actually returned. But JQXHR implements the Promise interface of JQuery, so it is also a Promise object.
done()
、
fail()
And
always()
done()
Adds a callback deferred.resolve()
that fail()
adds deferred.reject()
a callback. So when the Ajax call succeeds done()
, the added callback is executed, and the callback is executed when the call fails fail()
. However, the added callback will be executed regardless of success or not always()
.
Here done()
, fail()
and always()
both add callbacks in a similar way, which means that done()
fail()
always()
several callbacks that they add will execute sequentially, regardless of the number of times they are executed.
In general, Ajax is performed like this
// 禁用按钮以避免重复提交$("#theButton").prop({ disabled: true});// 调用 Ajax 提交数据,假设返回的是 JSON 数据var jqxhr = $.ajax("do/example", { type: "post", dataType: "json", data: getFormData()});jqxhr.done(function(jsonObject) { // Ajax 调用成功 console.log("success with data", jsonObject);}).fail(function() { // Ajax 调用失败 console.log("failed")}).always(function() { // 不管成功与否,都会执行,取消按钮的禁用状态 $("#theButton").prop({ disabled: false });});
The above is the most common use of the most common, but in a project is always so written Ajax, a little tired, a little agreement to wrap it up will be more convenient to use. First, let's say we define the JSON that is returned in this format:
{ "code": "int, 0 表示成功,其它值表示出错", "message": "string, 附加的消息,可选", "data": "object,附加的数据,可选}
Then app
define a method for the project's public class ajax
app.ajax = function(button, url, data) { if (button) { button.prop("disabled", true); } return $.ajax(url, { type: "post", dataType: "json", data: data }).done(function(json) [ if (json.code !== 0) { showError(json.message || "操作发生错误"); } }).fail(function() { showError("服务器错误,请稍后再试"); }).always(function() { if (button) { button.prop("disabled", false); } });};// 调用app.ajax("do/example", getFormData()).done(function(json) { if (json.code === 0) { // 只需要处理正确的情况啦 }});
However, it is still a bit uncomfortable, if you do not need to judge json.code === 0
the better. This one...... You can use a Deferred to handle it yourself:
app.ajax = function(button, url, data) { if (button) { button.prop("disabled", true); } var deferred = $.Deferred(); $.ajax(url, { type: "post", dataType: "json", data: data }).done(function(json) [ if (json.code !== 0) { showError(json.message || "操作发生错误"); deferred.reject(); } else { deferred.resolve(json); } }).fail(function() { showError("服务器错误,请稍后再试"); deferred.reject(); }).always(function() { if (button) { button.prop("disabled", false); } }); return deferred.promise();};// 调用app.ajax("do/example", getFormData()).done(function(json) { // json.code === 0 总是成立 // 正常处理 json.data 就好});
Note that this is not the result of a direct return $.ajax()
JQXHR object, it returns the Deferred
object of the new object promise
.
Review Ajax, now need to cut to the chase, find JQuery Promise and ES6 Promise close to the place- then()
.
Jquery
deferred.then()
Before jquery 1.8 (excluding 1.8, such as jquery 1.7.2), it deferred.then()
was a syntactic sugar that was put done()
and fail()
put together. JQuery modified the behavior in the 1.8 version to deferred.then()
make then()
the behavior similar to the Promise then()
. From the JQuery documentation you can see the 1.8 version change-kill callback and replace with filter:
// version added: 1.5, removed: 1.8deferred.then( doneCallbacks, failCallbacks )// version added: 1.7, removed: 1.8deferred.then( doneCallbacks, failCallbacks [, progressCallbacks ] )// version added: 1.8deferred.then( doneFilter [, failFilter ] [, progressFilter ] )
Callback can be simply treated as an event, the value is generally not changed after the callback, and the filter is different, a value passed in the filter and returned from the filter, may have changed. Let's give an example to illustrate
var deferred = $.Deferred();var promise = deferred.promise();promise.then(function(v) { console.log(`then with ${v}`);}).done(function(v) { console.log(`done with ${v}`);});deferred.resolve("resolveData");
Results in the JQuery 1.7.2
then with resolveDatadone with resolveData
Results in the JQuery 1.8.0
then with resolveDatadone with undefined
From the above, the deferred.then()
semantic and ES6 semantics of JQuery are Promise.then()
basically consistent. app.ajax
then()
It will help to understand the ES6 Promise if the above conversion is realized.
app.ajax = function(button, url, data) { if (button) { button.prop("disabled", true); } return $.ajax(url, { type: "post", dataType: "json", data: data }).then(function(json) { if (json.code !== 0) { showError(json.message || "操作发生错误"); return $.Deferred().reject().promise(); } else { return $.Deferred().resolve(json).promise(); } }, function() { showError("服务器错误,请稍后再试"); deferred.reject(); }).always(function() { if (button) { button.prop("disabled", false); } });};// 调用方式没变,用 done,也可以用 thenapp.ajax("do/example", getFormData()).done(function(json) { // json.code === 0 总是成立 // 正常处理 json.data 就好});
From JQuery Promise to ES6 Promise
The code above is too long to refine the key parts (motioned, not run)
var promise = $.ajax();promise.then(function(data) { // resolve return data.code ? new Promise().reject() : new Promise().resolve(data); // 如果没有错,就返回一个新的 promise,并使用 data 来 resolve, // 也可以直接返回 data, // 这样后面 then 的 resolve 部分才能收到数据}, function() { // rejected});// 调用阶段promise.then(function(data) { // 处理 data});
Perhaps you have not noticed, in fact the above code is basically the ES6 Promise. The following formally rewrite the above schematic code with ES6 Promise
var promise = new Promise(function(resolve, reject) { $.ajax().then(resolve, reject); // 上面这句没看懂?那换成这样你一定会懂 // $.ajax().then(function(data) { // resolve(data); // }, function() { // reject(); // });}).then(function(data) { return data.code ? Promise.reject() : Promise.resolve(data); // 这里 Promise.resolve(data) 同样可以直接替换为 data});// 调用没变promise.then(function(data) { // 处理 data});
What's the difference? Unconsciously will be ES6 Promise!
ES6 's Promise
The above has brought out the ES6 Promise, now only need to list the common methods as a reference can be
Note that the lowercase promise
representation of the Promise
object
new Promise(executor)
, a new Promise object is generated
executor(resolve, reject)
executor
, resolve
and reject
both are functions, in executor
which the return data is handled correctly, and resolve()
exception handling is returned directly or to the throw new Error(...)
reject()
data.
Promise.resolve(data)
, the Promise object is generated andresolve
Promise.reject()
, the Promise object is generated andreject
Reference
- ECMAScript Language specification-ecma-262 6th Edition
- Deferred-mozilla | MDN
- Promise-mozilla | MDN
- Deferred Object | JQuery Documentation
Learn from the similarities and differences between ES6 Promise and JQuery Deferred Promise