在JavaScript中代碼都是單線程執行的,所以JavaScript中全部的網絡操做、瀏覽器事件都必須異步執行。在Promise
以前JavaScript處理異步的方式都是回調函數。能夠說callback
的方式已經是深刻人心,那Promise
又是解決什麼問題的呢?看下面一段代碼:ajax
$.get('/getList',function(){ $.get('/getCount',function(){ $.get('/getDetail',function(){ //.... }) }) })
這段代碼就是傳統的callback
方式處理異步,能夠看到剛剛3級嵌套代碼層級就已經比較亂了,若是再加上一些邏輯代碼那簡直是沒法直視。這就是咱們常說的==回調地獄==問題。代碼可讀性低,難以維護,沒法複用。數組
Promise
的基本用法promise
var promise = new Promise((resolve,reject)=>{ setTimeout(function(){ //這裏異步操做已經執行完了,就能夠經過resolve告訴外界能夠進行其餘操做了 resolve('ok'); //reject('no'); },2000); }) promise.then(res=>{ console.log(res); // ok },err=>{ console.log(err); // no })
經過Promise
處理異步,先執行異步操做,不關心如何處理結果,經過Promise
對象的返回成功仍是失敗,在未來的某個時刻執行結果處理函數。代碼變得扁平化,且易讀易維護。瀏覽器
resolve && reject
上面代碼咱們經過 resolve 方法把 Promise 的狀態置爲完成態(Resolved),這時 then 方法就能捕捉到變化,並執行「成功」狀況的回調。
而 reject 方法就是把 Promise 的狀態置爲已失敗(Rejected),這時 then 方法執行「失敗」狀況的回調(then 方法的第二參數)。網絡
一樣三級回調的代碼咱們再使用Promise
重構一遍異步
new Promise((resolve,reject)=>{ $.get('/getList',res=>{ resolve(res); }); }).then(res=>{ return new Promise((resolve,reject)=>{ $.get('/getCount',res=>{ resolve(res); }); }); }).then(res=>{ return new Promise((resolve,reject)=>{ $.get('/getDetail',res=>{ resolve(res); }) }); }).then(res=>{ //... });
能夠看到不管有多少層回調,都不用互相嵌套,只須要等待Promise
對象「通知「執行便可。函數
當須要進行多步沒有關聯邏輯的異步操做時,可使用Promise.all
線程
Promise.all([ $.get('/getList'), $.get('/getCount'), $.get('/getDetail') ]).then(([data1,data2,data3])=>{ //then回調的參數是一個數組,順組數序就是異步操做書寫順序 console.log(data1,data2,data3); },err=>{ console.log(err); });
all
方法中的參數應該是Promise
對象,由於ajax
函數返回的對象就是promise對象因此這裏是能夠執行的;data1,data2,data3
是按照異步操做書寫順序返回);race
的用法與all
類似,不一樣點就是all
會等全部異步操做所有執行完後再執行then回調,而race
中只要有一個異步操做執行完成就馬上執行then回調。code
Promise.race([ new Promise(function(resolve, reject){ setTimeout(function(){ console.log('函數一執行!'); resolve('11'); }, 1000); }), new Promise(function(resolve, reject){ setTimeout(function(){ console.log('函數二執行!'); resolve('22'); }, 1200); }) ]).then(result=>{ console.log('then執行'); console.log(result); },err=>{ console.log(err); }); //執行結果爲: //函數一執行! //then執行 //11 //函數二執行!
能夠看到函數一執行明顯要比函數二快,因此執行了函數一後當即執行了then回調,==注意這時函數二依然會執行==,可是執行後不會再觸發then回調的執行。對象
then
。new Promise((resolve,reject)=>{ //... }).then(resSuccess=>{ //成功 },resError=>{ //失敗 });
catch
捕獲new Promise((resolve,reject)=>{ //... }).then(resSuccess=>{ //成功 }).catch(resError=>{ //失敗 });
==注==:catch
方式更經常使用,由於不單單能捕獲到reject傳遞的參數,還能夠捕獲到成功的回調中發生的錯誤。
jQuery 用 $.Deferred 實現了 Promise 規範。
function fn1() { var def = $.Deferred(); //執行異步操做 setTimeout(function () { console.log('函數1!'); def.resolve('函數1執行完畢回調'); //def.reject('函數1執行完畢回調'); }, 1000); return def.promise(); } //then方法第一個參數接收成功回調,第二個參數是接收失敗回調 fn1().then(res => { console.log(res); },err=>{ console.log(err); });
$.Deferred()
方法返回一個對象,咱們能夠稱之爲Deferred
對象,該對象包含一些方法如:then、done、fail 等。jQuery
就是用這個Deferred
對象來實現Promise
規範的。
對於多級回調的狀況也可使用then()
方法進行鏈式調用:
function fn1() { var def = $.Deferred(); //執行異步操做 setTimeout(function () { console.log('執行函數1!'); def.resolve('函數1執行完畢回調'); }, 1000); return def.promise(); }; function fn2() { var def = $.Deferred(); //執行異步操做 setTimeout(function () { console.log('執行函數2!'); def.resolve('函數2執行完畢回調'); }, 1000); return def.promise(); }; fn1().then(res => { console.log(res); //能夠鏈式調用的核心在於返回一個Deferred對象 return fn2(); }).then(res => { console.log(res); }); //執行函數1! //函數1執行完畢回調 //執行函數2! //函數2執行完畢回調
done() && fail()
done與fail的用法與then類似,實際就是一個語法糖。
function fn1() { var def = $.Deferred(); setTimeout(function () { console.log('執行函數1!'); def.resolve('函數1執行完畢回調'); // def.reject('函數1執行失敗回調'); }, 1000); return def.promise(); }; fn1().then(function (res) { console.log(res); }, function (err) { console.log(err); }); fn1().done(function (res) { console.log(res); }).fail(function (err) { console.log(err); });
always()Defferred
對象上還有一個always方法
,不管異步操做返回什麼結果都會執行always
回調。
function fn1() { var def = $.Deferred(); setTimeout(function () { console.log('執行函數1!'); def.resolve('函數1執行完畢回調'); // def.reject('函數1執行失敗回調'); }, 1000); return def.promise(); }; fn1().then(function (res) { console.log(res); }, function (err) { console.log(err); }).always(() => { console.log('不管成功失敗都會進入這裏'); });
因爲Promise的出現,jQuery的Deferred對象已經不多使用了。一些其餘用法在這也不一一舉例了,若是有興趣能夠去官網詳細瞭解。