1. Vorwort
Vor jQuery 1.5 verwendeten wir im Allgemeinen die folgenden zwei Methoden, wenn mehrere Ajax-Operationen erforderlich waren:
1).Serienaufruf Ajax
$.ajax({ success: function() { $.ajax({ success: function() { $.ajax({ //callbacks... }); }); });
Der Code in dieser Methode ist schlecht lesbar, ineffizient, undurchsichtig und kompliziert zu debuggen und zu beheben.
2). Rufen Sie Ajax parallel auf
var promises = []; $.ajax({ success: function() { promises.push('resolved'); check(); } }); $.ajax({ success: function() { promises.push('resolved'); check(); } }); $.ajax({ success: function() { promises.push('resolved'); check(); } }); var check = function() { //checks for all 3 values in the promises array }
Diese Methode eignet sich bereits sehr gut für Callback-Funktionsaufrufe. Sie ruft Daten parallel ab und ist gut lesbar. Die Nachteile sind langwieriger Code, schlechte Skalierbarkeit und eine hohe Komplexität bei der Fehlerbehebung und Fehlerbehebung.
Nach jQuery 1.5 wurden verzögerte Objekte hinzugefügt. Daher können die gleichen Anforderungen wie oben auf folgende Weise erreicht werden.
1) Versprechen
var address = $.ajax({}); var tweets = $.ajax({}); var facebook = $.ajax({}); render_side_bar = function(address, tweets, facebook){ //render sidebar } render_no_side_bar = function () { } $.when(address, tweets, facebook).then(render_side_bar, render_no_side_bar)
Es ist ersichtlich, dass der Code eine gute Lesbarkeit und hohe Skalierbarkeit aufweist und die Komplexität des Debuggens und der Fehlerbehebung erheblich reduziert.
Dann stellt sich die Frage: Was genau sind Versprechen und aufgeschobene Objekte?
2. Ausführliche Erklärung
2. Was ist ein zurückgestelltes Objekt?
Das verzögerte Objekt ist ein verzögertes Objekt. Es handelt sich um eine in jQuery Version 1.5 eingeführte Rückruffunktion. Es stellt einen bestimmten Vorgang dar, der ausgeführt werden muss, und stellt einige Methoden bereit, die Benutzern bei deren Verwendung helfen.
Das verzögerte Objekt ist die Implementierung der Promises-Schnittstelle. Das von allen Ajax-Versionen von jQuery 1.5 und höher zurückgegebene jqXHR-Objekt ist ein verzögertes Objekt.
2. Mehrere Vorteile von aufgeschobenen Objekten
2.1. Geben Sie mehrere Rückruffunktionen für denselben Vorgang an
Einer der Vorteile verzögerter Objekte besteht darin, dass Sie einer Operation mehrere Rückruffunktionen hinzufügen können, was in herkömmlichem Ajax nicht möglich ist.
$.ajax("test.html") .done(function(){ alert("first success callback!");} ) .fail(function(){ alert("there is an error!"); } ) .done(function(){ alert("second success callback!");} );
2.2. Geben Sie dieselbe Rückruffunktion für mehrere Vorgänge an
Der zweite Vorteil des verzögerten Objekts besteht darin, dass Sie dieselbe Rückruffunktion für mehrere Vorgänge angeben können, was mit herkömmlichem Ajax ebenfalls nicht möglich ist.
$.when($.ajax({}), $.ajax({})) .done(function(){ alert("success!"); }) .fail(function(){ alert("error!"); });
2.3. Rückruffunktion für Nicht-Ajax-Operationen
Der dritte Vorteil des verzögerten Objekts besteht darin, dass es nicht mehr auf Ajax-Operationen beschränkt ist (Ajax-Operation oder lokale Operation/asynchrone Operation oder synchrone Operation) das verzögerte Objekt verwenden und eine Rückruffunktion angeben kann.
Ein sehr typischer zeitaufwändiger Vorgang
var dfd = $.Deferred(); // create a deferred object var wait = function(dtd){ var tasks = function(){ alert("over!"); dtd.resolve(); // change the state of the deferred object from pending to resolved }; setTimeout(tasks,50000); return dtd; };
$.when(wait(dtd)) .done(function(){ alert("success!"); }) .fail(function(){ alert("error!"); });
2.4. Kettenruf
Die traditionelle Ajax-Operation in jQuery sieht folgendermaßen aus:
$.ajax({ url: "", success: function(){ alert("success!"); }, error:function(){ alert("error!"); } });
Erfolg gibt die Rückruffunktion an, nachdem die Ajax-Operation erfolgreich war, und Fehler gibt die Rückruffunktion an, nachdem die Ajax-Operation fehlgeschlagen ist. Vor jQuery 1.5 gaben Ajax-Operationen ein XMLHTTPRequest-Objekt zurück und unterstützten keine Kettenoperationen. Ab Version 1.5 gibt die Ajax-Operation das jqXHR-Objekt zurück, bei dem es sich um ein verzögertes Objekt handelt. Ein wesentlicher Vorteil des verzögerten Objekts besteht darin, dass es Kettenoperationen ausführen kann, da alle Methoden des verzögerten Objekts verzögerte Objekte zurückgeben.
Die aktuelle Ajax-Operation wird wie folgt geschrieben:
$.ajax({}) .done(function(){ alert("success!"); }) .fail(function(){ alert("fail!"); });
Beim Vergleich der beiden Schreibmethoden ist deutlich zu erkennen, dass done() der Erfolgsmethode der herkömmlichen Ajax-Operation und fail() der Fail-Methode der herkömmlichen Ajax-Operation entspricht. Im Vergleich zu herkömmlichen Schreibmethoden ist die Lesbarkeit des Codes verbessert.
3.Methoden verzögerter Objekte
3.1 Grundlegende Verwendung
(1).Verzögertes Objekt generieren
var dfd = $.Deferred(); //ein verzögertes Objekt erstellen
(2).Status des zurückgestellten Objekts
Zurückgestellte Objekte haben drei Zustände
ausstehend: zeigt an, dass sich der Vorgang in einem unvollendeten Zustand befindet und jedes zurückgestellte (zurückgestellte) Objekt im ausstehenden Zustand beginnt.
behoben: zeigt an, dass der Vorgang erfolgreich war.
abgelehnt: zeigt an, dass der Vorgang fehlgeschlagen ist.
Die Methode state() gibt den aktuellen Status des zurückgestellten Objekts zurück.
$.Deferred().state(); // 'pending' $.Deferred().resolve().state(); // 'resolved' $.Deferred().reject().state(); // 'rejected'
(3).Ändern Sie den Status des zurückgestellten Objekts
Rufen Sie deferred.resolve() oder deferred.resolveWith() auf, um Deferred in den gelösten Zustand umzuwandeln und alle doneCallbacks in der Einstellung sofort auszuführen.
var callbackFunc = function(){console.log(arguments[0]);} var dfd = $.Deferred(); dfd.done(callbackFunc); dfd.resolve("hello"); //'hello'
Rufen Sie deferred.reject() oder deferred.rejectWith() auf, um Deferred in den Status „Abgelehnt“ umzuwandeln und alle failCallbacks in der Einstellung sofort auszuführen.
var callbackFunc = function(){console.log(arguments[0]);} var dfd = $.Deferred(); dfd.fail(callbackFunc); dfd.reject("fail"); //'fail'
(4).Rückruffunktion binden
Wenn sich der Status des verzögerten Objekts ändert, wird die Rückruffunktion ausgelöst. Alle diesem Objekt mit deferred.then(), deferred.always(), deferred.done() oder deferred.fail() hinzugefügten Rückrufe werden zur Ausführung in die Warteschlange gestellt.
ausstehend-->aufgelöst, führen Sie alle doneCallbacks (angegeben durch done()) in den Einstellungen aus und die Parameter werden durch aufgelöst an doneCallbacks übergeben.
ausstehend -> abgelehnt, führen Sie alle failCallbacks (angegeben durch fail()) in den Einstellungen aus und die Parameter werden durch gelöst an failCallbacks übergeben.
pending-->resolved/rejected, führt die durch Always() angegebenen Rückrufe aus und die Parameter werden von „aufgelöst“ an die Rückrufe übergeben.
var f1 = function(){console.log("done");}, f2 = function(){console.log("fail");}, f3 = function(){console.log("always");}; var dfd = $.Deferred(); dfd.done(f1).fail(f2).always(f3); //if dfd.resolve(); //'done' 'always' //if dfd.reject(); //'fail' 'always'
如果在状态更改后附件一个callback则会立即执行callback,因此不必担心deferred对象何时被resolved或者rejected,因为无论何时,参数都会正确地传递给callbacks。
var fun1 = function(){console.log(arguments[0]);}, fun1 = function(){console.log(arguments[0]);}; var dfd = $.Deferred(); dfd.done(fun1); dfd.resolve("hello"); //'hello' dfd.done(fun2); //'hello'
3.2.deferred对象的方法
(1)$.Deferred([beforeStart]) -- 创建一个deferred对象,参数类型为Function,是一个在构造函数之前调用的函数。
var func = function(){console.log("start");} var dfd = $.Deferred(func); //'start' create a deferred object
(2)deferred.done(doneCallbacks [,doneCallbacks]) -- 当deferred(延迟)对象解决时,调用添加处理程序。
args:接受一个或者多个参数,所有的参数都可以是一个单一的函数或者函数数组,当deferred(延迟)对象解决时,doneCallbacks被调用。回调是依照他们添加的顺序执行的。
var func1 = function(){console.log("1");}, func2 = function(){console.log("2");}, func3 = function(){console.log("3");}; var dfd = $.Deferred(); dfd.done([func1,func2],func3,[func2,func1]); dfd.resolve(); // "1 2 3 2 1"
(3)deferred.fail(failCallbacks [,failCallbacks]) -- 当deferred(延迟)对象拒绝时,调用添加处理程序。
args:接受一个或者多个参数,所有的参数都可以是一个单一的函数或者函数数组,当deferred(延迟)对象拒绝时,failCallbacks被调用。回调是依照他们添加的顺序执行的。
var func1 = function(){console.log("1");}, func2 = function(){console.log("2");}, func3 = function(){console.log("3");}; var dfd = $.Deferred(); dfd.fail([func1,func2],func3,[func2,func1]); dfd.reject(); // "1 2 3 2 1"
(4)deferred.resolve(args) and deferred.resolveWith(context [,args]) -- 解决Deferred(延迟)对象,并根据给定的args参数(resolveWith给定context)调用任何doneCallbacks。
参数:args -- type(object),传递给回调函数(doneCallbacks)的可选的参数,
context -- type(object),Context(上下文)作为this对象传递给完成回调函数(doneCallbacks)。
var func = function(arg){console.log(arg);}; $.Deferred().done(func).resolve("done!"); //'done!' var func = function(arg1,arg2){console.log(arg1.name + ',' + arg2);}; $.Deferred().done(func).resolve({name:'Lucy'},'How are you!'); // 'Lucy,How are you!'
resolve和resolveWith的区别就等同于fire和fireWith的区别。
var func = function () { console.log(this.name + ',' + arguments[0] + ' ' + arguments[1] + ' ' + arguments[2]); }; $.Deferred().done(func).resolveWith({ name: "Lucy" }, ["How", "are", "you!"]);//'Lucy,How are you!'
(5)deferred.reject(args) and deferred.rejectWith(context [,args]) -- 拒绝Deferred(延迟)对象,并根据给定的args参数(rejectWith给定context)调用任何failCallbacks。
参数:args -- type(object),传递给回调函数(doneCallbacks)的可选的参数,
context -- type(object),Context(上下文)作为this对象传递给完成回调函数(doneCallbacks)。
var func = function(arg){console.log(arg);}; $.Deferred().fail(func).reject("error!"); //'error!' var func = function(ctx,arg){console.log(ctx.name + ',' + arg);}; $.Deferred().fail(func).reject({name:'Mark'},'What happend!'); // 'Mark,What happend!'
reject和rejectWith的区别就等同于fire和fireWith的区别。
var func = function () { console.log(this.name + ',' + arguments[0] + ' ' + arguments[1]); }; $.Deferred().fail(func).rejectWith({ name: "Mark" }, ["what", "happend!"]); // 'Mark,What happend!'
(6)deferred.promise([target]) -- 返回Deferred(延迟)的Promise(承诺)对象。
参数可选,无参数时返回一个Promise(承诺)对象,Promise(承诺)对象仅会暴露那些需要绑定额外的处理或判断状态的延迟方法(then, done, fail, always,pipe, progress, state,和 promise)时,并不会暴露任何用于改变状态的延迟方法(resolve, reject, notify,resolveWith, rejectWith, 和 notifyWith)。使用Promise(承诺)会阻止其他人破坏你制造的promise。
function asyncEvent() { var dfd = jQuery.Deferred(); // Resolve after a random interval setTimeout(function () { dfd.resolve("hurray"); }, Math.floor(400 + Math.random() * 2000)); // Reject after a random interval setTimeout(function () { dfd.reject("sorry"); }, Math.floor(400 + Math.random() * 2000)); // Show a "working..." message every half-second setTimeout(function working() { if (dfd.state() === "pending") { dfd.notify("working... "); setTimeout(working, 500); } }, 1); // Return the Promise so caller can't change the Deferred return dfd.promise(); } // Attach a done, fail, and progress handler for the asyncEvent $.when(asyncEvent()).then( function (status) { alert(status + ", things are going well"); }, function (status) { alert(status + ", you fail this time"); }, function (status) { alert(status); } );
有参数时,会将事件绑定到参数上,然后返回该参数对象(返回的实际是一个扩展的Promise(承诺)对象)。
var obj = { hello: function (name) { alert("Hello " + name); } }, // Create a Deferred dfd = $.Deferred(); // Set object as a promise dfd.promise(obj); // Resolve the deferred dfd.resolve("John"); // Use the object as a Promise obj.done(function (name) { obj.hello(name); // will alert "Hello John" }).hello("Karl");
(7)$.when(deferreds) -- 提供一种方法来执行一个或多个对象的回调函数。
参数:type(Deferred),一个或多个延迟对象,或者普通的JavaScript对象。
参数仅传入一个单独的Deferred对象,返回它的Promise对象。
function func() { var dfd = $.Deferred(); setTimeout(function () { dfd.resolve("hurry"); }, 500); return dfd.promise(); }; $.when(func()).done(function (arg) { alert(arg); /*alert "hurry"*/ });
参数传入一个非Deferred和Promise对象,那么该参数会被当成一个被解决(resolved)的延迟对象,并且绑定到上面的任何doneCallbacks都会被立即执行。
$.when( { name: 123 } ).done( function(arg) { alert(arg.name); } /* alerts "123" */ );
无参数,返回一个resolved(解决)状态的Promise对象。
$.when().state(); // "resolved"
参数为多个Deferred对象,该方法根据一个新的“宿主” Deferred(延迟)对象,跟踪所有已通过Deferreds聚集状态,返回一个Promise对象。当所有的延迟对象被解决(resolve)时,“宿主” Deferred(延迟)对象才会解决(resolved)该方法,或者当其中有一个延迟对象被拒绝(rejected)时,“宿主” Deferred(延迟)对象就会reject(拒绝)该方法。
var d1 = $.Deferred(); var d2 = $.Deferred(); $.when( d1, d2 ).done(function ( v1, v2 ) { console.log( v1 ); // "Fish" console.log( v2 ); // "Pizza" }); d1.resolve( "Fish" ); d2.resolve( "Pizza" );
(8)deferred.then(doneFilter [,failFilter] [,progressFilter]) -- 当Deferred(延迟)对象解决,拒绝或仍在进行中时,调用添加处理程序。
参数:
doneFilter -- type(Function),当Deferred(延迟)对象得到解决时被调用的一个函数。
failFilter -- type(Function),当Deferred(延迟)对象拒绝时被调用的一个函数,可选。
progressFilter -- type(Function),当Deferred(延迟)对象生成进度通知时被调用的一个函数,可选。
其实,then方法可以理解成,把done(),fail(),progress()合在一起写。
var filterResolve = function () { var dfd = $.Deferred(), filtered = dfd.then(function (value) { return value * 2; }); dfd.resolve(5); filtered.done(function (value) { console.log(value); }); }; filterResolve(); //'10' var defer = $.Deferred(), filtered = defer.then(null, function (value) { return value * 3; }); defer.reject(6); filtered.fail(function (value) { alert("Value is 3*6 = " + value); });
(9)deferred.always(alwaysCallbacks [,alwaysCallbacks]) -- 当Deferred(延迟)对象解决或拒绝时,执行alwaysCallbacks。
顾名思义,只要Deferred对象的状态发生更改(解决或者拒绝)均会调用alwaysCallbacks。
(10)deferred.state() -- 获取一个Deferred(延迟)对象的当前状态,不接受任何参数。
$.Deferred().state();//"pending"
上面讲述过deferre(延迟)对象的三种状态,这个方法对于debug非常有用,例如,在准备reject一个deferred对象之前,判断它是否处于resolved状态。
(11)deferred.notify(args) and deferred.notifyWith()
(12)deferred.progress()
(13)deferred.pipe()
(14).promise()
(15)deferred.isRejected() 和 deferred.isResolved() -- 从jQuery 1.7开始被弃用,较新版本的jQuery类库中已经被删除,可以使用state()方法代替这两个方法。
(16)deferred.pipe() -- 从jQuery 1.8开始被弃用。
4.什么情况下使用deferred对象和Promises?
上面讲了很多,那么我们究竟在什么情况下使用Deferred对象和Promises对象呢?
(1)复杂的动画
不知道动画什么时候结束,但是又必须在动画结束的时候做一些操作或者是启动其他的动画,这种情况下,如果采用其他的方式,很容易导致代码可读性差,尤其是还夹带着一些其它的操作,比如渲染、表单操作等,现在jQuery会为你的动画操作返回一个Promise,这样这些动画可以进行链式操作。
(2)处理队列
function wait(ms) { var deferred = $.Deferred(); setTimeout(function(){deferred.resolve()}, ms); return deferred.promise(); } wait(1500).then(function () { // After 1500ms this will be executed });
(4)典型的Ajax操作
$.when($.ajax({}), $.ajax({})) .done(function(){ alert("success!"); }) .fail(function(){ alert("error!"); });
(5)一些耗时的大循环操作
以上就是本文的全部内容,希望对大家的学习有所帮助。