私の技術レベルには限界がありますので、間違いがあればご指摘ください。
ES6ではすでに遅延オブジェクトPromiseが実装されていますが、今日の主役はJQの遅延オブジェクトで、ルーチンも実は同じです。突飛な例を見てみましょう:
<button id="add">add</button><button id="remove">remove</button> <div id="content"></div>
$(function(){ var dfd = new $.Deferred(); var add = $("#add"); var remove = $("#remove"); var content = $("#content"); add.click(function(){ var span = $("<span>我是点击按钮创建的元素</span>"); $("span").length==0&&$("body").append(span); dfd.resolve(); }) remove.click(function(){ var span = $("span"); span&&span.remove(); }) dfd.done(function(){ $("span").css("color","red"); }) })
次に、追加ボタンをクリックすると、span 要素が追加され、色が赤に変わることがわかります。次に、コード内の異質なもの、つまり、イベント追加関数の最初の var dfd = new $.Deferred(); と dfd.resolve()、および最後の dfd.done(function(){ $(") を調べました。スパン").css("色","赤");})。
$.Deferred() が今日の紹介の焦点です、つまり JQ の遅延オブジェクトです。いわゆる遅延とは、将来の特定のイベントで実行できることを意味します。上記コードの処理の流れを見てみましょう。上記コードでは、新しく作成した遅延オブジェクトの dfd.done() メソッドのパラメータ位置に無名関数式を渡し、クリックイベントハンドラの実行時に dfd を呼び出しています。このプロセスでは、dfd が関数を解決位置に配置していることがわかります。 dfd は関数の実行順序を変更できる遅延オブジェクトです。
上記のコードをよく考えてみると、色を変更するためのコードを関数に配置しており、それをクリックするだけでこの関数を呼び出すことができることがわかります。鳥にとっては書くのがとても面倒です。実際、遅延オブジェクトの最も一般的な使用法は AJAX です。上記のコードでは、[追加] をクリックした後、[削除] をクリックしてから [追加] をクリックしますが、このとき単語が赤にならないのは、状態が変化した後に遅延オブジェクトが無効になるためです。率直に言って、それは1回限りの使用です。
遅延オブジェクトの使用
JQ は、通常、遅延オブジェクトの機能を Deferred または Promise と呼びますが、正確には、Promise は Deferred から派生したサブクラスです。
これを使用するときは、まず遅延オブジェクトを作成します: var dfd = new $.Deferred()。
遅延オブジェクト dfd には、pending、resolved、rejected の 3 つの状態があります。dfd オブジェクトの state メソッド dfd.state() を使用して、この時点の状態を確認できます。
dfd が作成された後、そのステータスは保留中になります。resolve メソッド: dfd.resolve() を呼び出した後、そのステータスは解決済みになり、dfd が拒否メソッドを呼び出した後、dfd.done() の関数が実行されます。 dfd .reject() はステータスを拒否に変更してから dfd.fail() のメソッドを実行しますが、保留から解決または拒否に変更された後も dfd オブジェクトは変化しません。これが上記のコードの理由です。最初のクリック後のみ赤色になります。
開始コードを見てみましょう。 dfd.done() は、実行する関数をクリックした後、dfd のステータスを解決する関数を定義します。保留中から解決済みに変更するとメソッドが実行され、色が赤に変わります。 dfd.resolve() と dfd.done() の間でパラメーターを渡すことができます。次に、開始コードにいくつかの変更を加えます。//done里面的修改如下 dfd.done(function(color){$("span").css("color",color)}) //点击事件的处理函数修改如下 dfd.resolve("green");
dfd.done(function(){ var span = $("<span>我是点击按钮创建的元素</span>"); $("span").length==0&&$("body").append(span); }) .done(function(color){ $("span").css("color",color)}); })
var dfd = new $.Deferred(); dfd.done(function(){console.log(1)}); dfd.done(function(){console.log(2)}); console.log("resolve before"); dfd.resolve(); console.log("resolve after"); dfd.done(function(){console.log(3)}); //resolve before,1,2,resolve after,3
$.ajax({ url:"x/y", type:"post", data:"{...}", contentType:"application/json; charset=utf-8", success:function(){}, error:function(){} })
已经知道延迟对象可以改变代码的执行顺序,假如我们又下面的代码:
$.ajax({ url:"取数据", type:"post", contentType:"xxx" }).done(function(data){ $.ajax({ url:"利用data取数据", data:data, type:"post", contentType:"xxxx" }).done(function(data){ use data to _do sth... }) })
我们会发现嵌套的有点多了,我们就可以利用延迟对象让他看起来更加好看一点:
var dfd = new $.Deferred(); $.ajax({ url:"取数据", type:"post", contentType:"xxx" }).done(function(data){ dfd.resolve(data); }) dfd.done(function(data){ $.ajax({ url:"利用data取数据", data:data, type:"post", contentType:"xxxx" }).done(function(data){ use data to _do sth... }) })
没有延迟对象我们一样能完成需要的功能,此时我们就需要一层一层嵌套我们处理过程了,而有了延迟对象我们就可以避免这种事了,他可以轻松控制代码的执行顺序,让代码看起来更请清晰。你可能会说我封装函数在合适的地方调不就行了,如果自己看自己写的代码没问题,但是换一个人他的滚动条可能就一直上上下下了。
延迟对象的里一个作用就是可以合并AJAX的调用,比如一个接口取数据A另一个接口取数据B,AB都取到之后我们在利用这些数据做一些喜欢做的事,我们就可以利用延迟对象轻松实现。此时我们就可以利用JQ的$.when()来实现。$.when()就跟他的名字一样-当什么的时候-,他的参数可以是Promise对象,也可以是字符串(很少遇到不在介绍),他的返回结果也是一个Promise对象,下面看一个小例子:
var allData = {}; var dataA = $.ajax({ url:"获取A的URL", type:"post", }).done(function(data){ allData.a = data; }); var dataB = $.ajax({ url:"获取B的URL", type:"post", }).done(function(data){ allData.b = data; }); $.when(dataA,dataB).done(function(){ use allData to _do sth... });
allData是保存所有数据的一个集合,dataA是第一个AJAX返回的Promise对象,dataB是第二个。$.when()的done方法执行的唯一条件就是dataA和dataB都执行成功。
补充:dfd还有一对组合就是notify+progress当dfd对象的状态处于pending时可以调用dfd.nothfy(),调用之后dfd.progress()里面的函数会执行,只要dfd处于pending状态dfd.notify()就可以一直调用,同样也可以传递参数。