1 Untuk membawa kembali ke syurga dari neraka panggilan balik, jQuery juga memperkenalkan konsep Janji. Promise ialah abstraksi yang menjadikan tingkah laku tak segerak kod lebih elegan Dengannya, kita boleh menulis kod tak segerak sama seperti menulis kod segerak. jQuery telah melaksanakan spesifikasi CommonJS Promise/A sebagai penyelesaian berwajaran tinggi sejak versi 1.5, tetapi ia tidak dilaksanakan dengan ketat mengikut spesifikasi dan terdapat beberapa perbezaan API.
Baiklah, mari kita lihat ciri-ciri mereka (contoh dalam artikel ini adalah berdasarkan jquery versi 1.8 ke atas).
2. ContohApabila menulis animasi pada masa lalu, kami biasanya melakukan ini:
$('.animateEle').animate({ opacity:'.5' }, 4000,function(){ $('.animateEle2').animate({ width:'100px' },2000,function(){ // 这样太伤了 $('.animateEle3').animate({ height:'0' },2000); }); });
Mari kita lihat penyelesaian yang disediakan oleh jQuery.
var animate1 = function() { return $('.animateEle1').animate({opacity:'.5'},4000).promise(); }; var animate2 = function() { return $('.animateEle2').animate({width:'100px'},2000).promise(); }; var animate3 = function(){ return $('.animateEle3').animate({height:'0'},2000).promise(); }; // so easy,有木有,so clear,有木有 $.when(animate1()).then(animate2).then(animate3);
Namun, beberapa butiran tidak didedahkan dalam kod di atas Jika kita tidak berhati-hati, mudah untuk melakukan kesilapan dan kita tidak akan mendapat kesan melengkapkan animasi dalam susunan yang kita inginkan. Mari kita fahami sepenuhnya kaedah janji dan objek tertunda yang disediakan oleh jQuery dan lihat cara menggunakannya.
3. Janji dan kaedah objek tertundaObjek janji sebenarnya adalah kes khas objek tertunda, kerana objek janji tidak boleh menukar keadaan tak segerak, tetapi objek tertunda boleh. Ini jelas tercermin dalam reka bentuk kaedah mereka.
1.kaedah objek janjiBiasanya, untuk kaedah berkaitan DOM, animasi, ajax, kita boleh menggunakan kaedah janji. Memanggil kaedah janji mengembalikan objek janji. Kaedah janji boleh dipanggil dalam rantai.
Terdapat tiga kaedah biasa objek janji: selesai, gagal dan kemudian.
Jangan lupa tentang kaedah lain Terdapat terlalu banyak kaedah antara muka dalam jquery, yang pada pendapat saya agak bertele-tele Sama seperti kaedah awal acara mengikat, mewakilkan dan mengikat tidak semuanya dikelaskan pada akhirnya. Adakah di sini untuk menjaganya?
Contoh kod, seperti berikut:
(1) DOM menggunakan kaedah janji:
var box=$('#box'); box.promise().done(function(ele){ console.log(ele);//jQuery box });
$.post('/',{}).done(function(data){ console.log('请求成功'); }).fail(function(){ console.log('请求错误'); });
Jadi apakah perbezaan antara Tertunda dan Janji? Seperti yang anda lihat sebelum ini, janji ialah objek yang dikembalikan oleh fungsi tak segerak. Apabila anda ingin menulis fungsi sedemikian sendiri anda perlu menggunakan tertunda.
Objek tertunda boleh melakukan perkara yang sama seperti objek janji, tetapi ia mempunyai dua fungsi untuk mencetuskan fungsi done() dan fail().
Objek tertunda mempunyai fungsi resolve() untuk mengendalikan hasil yang berjaya dan melaksanakan fungsi yang berkaitan dengan done(). Fungsi reject() digunakan untuk mengendalikan keputusan yang gagal dan melaksanakan fungsi yang berkaitan dengan fail().
Anda boleh menyediakan parameter untuk kedua-dua fungsi resolve() dan reject(), dan kemudian kedua-duanya akan dihantar ke fungsi panggil balik yang berkaitan dengan done() dan fail().
Objek Promise tidak mempunyai fungsi resolve() dan reject(). Ini kerana anda meletakkan janji dalam skrip lain dan anda tidak mahu janji itu menyelesaikan atau menolak janji.
Berikut ialah contoh mudah tertunda. html hanyalah div kosong mudah dengan atribut id "hasil".
$('#result').html('waiting...'); var promise = wait(); promise.done(result); function result() { $('#result').html('done'); } function wait() { var deferred = $.Deferred(); setTimeout(function() { deferred.resolve(); }, 2000); return deferred.promise(); }
Untuk objek tertunda, iaitu objek yang dibuat menggunakan kaedah $.Deferred() dan kaedah $.when(), terdapat kaedah yang biasa digunakan berikut:
resolve , reject , notify ; done , fail , progress ;
Sebab mengapa mereka diformatkan seperti ini adalah kerana ia sepadan, iaitu: kaedah penyelesaian akan mencetuskan pelaksanaan panggilan balik selesai, menolak akan mencetuskan panggilan balik gagal, dan memberitahu akan mencetuskan panggilan balik kemajuan.
Lihat kod terus:
我们看到了,上面的代码中,在 wait 函数中,返回的是个 promise 对象,而不是 deferred 对象。
要知道, promise 对象是没有 resolve , reject , notify 等方法的,也就意味着,你无法针对 promise 对象进行状态更改,只能在 done 或 fail 中进行回调配置。所以,你如果这么调用 wait(2500).resolve() 将会报错,因为 wait(2500) 返回的是个 promise 对象,不存在 resolve 方法。
但是,这么做,有个好处,我们把 dtd 这个 deferred 对象放在了 wai t函数中,作为了局部变量,避免了全局的污染;进一步通过 promise 方法,转化 dtd 这个 deferred 对象为 promise 对象,避免了函数 wait 外部可能发生的状态更改(假如我们确实有这个需求)。
比如:
var wait = function(ms) { var dtd = $.Deferred(); setTimeout(dtd.resolve, ms); // setTimeout(dtd.reject, ms); // setTimeout(dtd.notify, ms); return dtd; //此处也可以直接返回dtd }; wait(2500).reject().fail(function(){ console.log('失败了...............'); });
我们在外部更改了 wait 返回的 deferred 对象的状态,这样必然触发该对象的 fail 回调函数。
对于 always 方法,从字面意思上就很容易理解, deferred 对象无论是 resolve 还是 reject ,都会触发该方法的回调。
3.其它共性
此处讲讲 then 和 $.when 方法的使用。它们对 promise 对象也适用。
$.when 方法接受多个 deferred 对象或者纯javascript对象,返回 promise 对象。
then 方法依次接受三个回调,分别为 deferred 对象 resolve , reject , notify 后触发的回调,返回一个 promise 对象。注意,必须传入函数,而该函数只有返回一个 promise 对象,才能够让异步事件按照预期顺序来执行。
我们来看看最开始的动画示例代码, $.when(animate1()).then(animate2).then(animate3) , $.when 方法中接受了一个 animate1 的函数执行结果,也就是得到了一个 promise 对象,而后的 then 中,则只是接受了一个变量名,这样得到的结果是一个匿名的函数体,而该函数中返回的是 promise 对象。正好符合了我们对 then 接受参数的要求。
假如我们把执行语句改成: $.when(animate1()).then(animate2()).then(animate3()) ,这样造成的结果就是三个动画同步执行了。与 $.when(animate1(),animate2(),animate3()) 无异。
既然 then 是如此要求,那么与 then 方法类似的 done , fail , progress 也是一样的。