摘要:雖然js已經出了ES6,ES7等等版本,從而也誕生了新的異步對象->promise,可是基礎仍是要終結的,這一片就來回顧一下ajax以及ajax的異步對象->deferred。ajax
1.傳統ajaxapi
傳統模式$.ajax()接受參數爲一個對象,該對象包含了callback(success和error)promise
栗子:異步
1 function toJson(data) { 2 document.write('<pre><code>' + JSON.stringify(data) + '</code></pre>'); 3 } 4 $.ajax({ 5 url: "http://yapi.demo.qunar.com/mock/10343/getinfo", 6 success: function (data) { 7 toJson(data); 8 }, 9 error: function (error) { 10 console.log('error'); 11 } 12 });
這裏安利一個第三方平臺YAPI,能夠經過YAPI模擬server端。函數
運行結果:url
2.隨着jQuery的改進,新的寫法誕生了spa
栗子:code
1 function toJson(data) { 2 document.write('<pre><code>' + JSON.stringify(data) + '</code></pre>'); 3 } 4 $.ajax("http://yapi.demo.qunar.com/mock/10343/getinfo") 5 .done(function(data){ 6 toJson(data); 7 }) 8 .fail(function(e){ 9 console.log(e); 10 })
運行結果:server
增長了鏈式用法。這是爲啥呢。由於jQuery在1.5.0版本之後增長了deferred對象,支持了鏈式調用方式。對象
3.增長了多個延遲函數公用一個回調函數,因而$.when()誕生了。
栗子:
1 function toJson(arr) { 2 arr.forEach(a => { 3 document.write('<pre><code>' + JSON.stringify(a) + '</code></pre>'); 4 }) 5 } 6 $.when($.ajax("http://yapi.demo.qunar.com/mock/10343/getinfo"), 7 $.ajax("http://yapi.demo.qunar.com/mock/10343/getinfo")) 8 .done(function (data, data2) { 9 toJson([data[0], data2[0]]); 10 }) 11 .fail(function (e) { 12 console.log(e); 13 })
結果:
這裏若是兩個ajax若是其中有一個失敗則會調用fail的callback,到這裏若是異步不是ajax呢,是setTimeout呢~
栗子:
1 function wait() { 2 var delayFn = function () { 3 console.log('over.'); 4 }; 5 setTimeout(delayFn, 5000); 6 };
要知道執行函數wait的時候,delayFn會以一個新的宏任務重新扔到一個事件隊列裏,這時兩個函數變成爲了異步,那麼這時候出現一個新的函數,如何控制新的函數要執行與延遲函數以後呢。
方式1:講函數寫在延遲函數內,這不廢話嗎。
方式2:若是與wait在同屬一個宏任務呢?答案是利用$.when(),以微任務的形式存在。這樣等延遲函數執行完再去執行,就是咱們上面栗子3的形式了。
栗子:
1 function wait(dtd) { 2 console.log(new Date()) 3 var delayFn = function () { 4 }; 5 setTimeout(delayFn, 5000); 6 }; 7 $.when(wait()) 8 .done(function (data) { 9 console.log(new Date()); 10 }) 11 .fail(function (e) { 12 console.log(e) 13 })
執行結果:
事實上並無等延遲函數執行完,才進入的回調函數,彷佛直接就執行了回調函數,這是爲啥呢?
緣由是:$.when()接受的對象必須是deferred對象,不然會當即執行回調函數。改進以下。
栗子:
1 var dtd = $.Deferred(); 2 function wait(dtd) { 3 console.log(new Date()) 4 var delayFn = function () { 5 dtd.resolve(); 6 }; 7 setTimeout(delayFn, 5000); 8 return dtd; 9 }; 10 $.when(wait(dtd)) 11 .done(function (data) { 12 console.log(new Date()); 13 }) 14 .fail(function (e) { 15 console.log(e) 16 })
運行結果:
deferred對象此外還有兩個方法分別是:reject()、promise()
resolve:改變deferred對象的狀態,執行done callback。
reject:reject()與reslove()方法同樣,同爲改變deferred對象的狀態,當狀態爲reject時,這執行fail callback。
promise:從新生成deferred對象。
4.promise對象
我猜ES6也是根據這個詞兒誕生的promise對象,嘿嘿。
上面栗子能夠看到dtd是外部傳入的對象,在wait之外就能夠改變deferred對象狀態,直接執行回調函數
栗子:
1 function toJson(arr) { 2 arr.forEach(a => { 3 document.write('<pre><code>' + JSON.stringify(a) + '</code></pre>'); 4 }) 5 } 6 var dtd = $.Deferred(); 7 function wait(dtd) { 8 console.log(new Date()) 9 var delayFn = function () { 10 dtd.resolve(); 11 }; 12 setTimeout(delayFn, 5000); 13 return dtd; 14 }; 15 $.when(wait(dtd)) 16 .done(function (data) { 17 console.log(new Date()); 18 }) 19 .fail(function (e) { 20 console.log('error' + ' time:' + new Date()) 21 }) 22 dtd.reject();
執行結果:
能夠看到在外面修改deferred狀態就會當即執行fail callback函數了。那麼如何避免呢~,咱們利用promise() 從新生成一個deferred對象。
栗子:
1 function toJson(arr) { 2 arr.forEach(a => { 3 document.write('<pre><code>' + JSON.stringify(a) + '</code></pre>'); 4 }) 5 } 6 var dtd = $.Deferred(); 7 var waitDtd = function wait(dtd) { 8 console.log(new Date()) 9 var delayFn = function () { 10 dtd.resolve(); 11 }; 12 setTimeout(delayFn, 5000); 13 return dtd.promise(); 14 }; 15 $.when(waitDtd) 16 .done(function (data) { 17 console.log(new Date()); 18 }) 19 .fail(function (e) { 20 console.log('error' + ' time:' + new Date()) 21 }) 22 waitDtd.reject();
over~