全手打原創,轉載請標明出處:http://www.javashuo.com/article/p-cjmwmnvf-hn.html,多謝,=。=~ html
axios用多了就開始疑惑它裏面究竟是個啥,雖然總被告知它就是基於ajax的封裝,但掐指一算,事情應該沒這麼簡單,因而開始深挖,挖着挖着就挖到了Promise。畢竟axios的官方描述是這樣的:Promise based HTTP client for browser and node.js。而axios其中一個特色就是Supports the Promise API,之前只知道promise是一種替代層層回調的解決方案,但如今看來我認爲頗有必要詳細的研究一下。node
背景ios
在JavaScript的世界中,全部代碼都是單線程執行的。該特性致使JavaScript的全部網絡操做,瀏覽器事件,都必須是異步執行(不然容易發生阻塞)。異步執行能夠用回調函數實現,該方式會在未來的某個時間點觸發一個函數調用(回調)。但異步執行中的回調並不利於代碼複用,例如:ajax
request.onreadystatechange = function () { if (request.readyState === 4) { if (request.status === 200) { return success(request.responseText); } else { return fail(request.status); } } }
但若是是這樣的鏈式寫法就會好不少(先統一執行AJAX邏輯,不關心如何處理結果,而後,根據結果是成功仍是失敗,在未來的某個時候調用success函數或fail函數):axios
var ajax = ajaxGet('http://...'); ajax.ifSuccess(success) .ifFail(fail);
什麼是Promise?promise
上述「承諾未來會執行」的對象在JavaScript中稱爲Promise對象,它有各類開源實現,但後面ES6將其寫進了語言標準,統一了用法,原生提供了Promise對象,由瀏覽器直接支持。瀏覽器
Promise對象表明一個異步操做,有三種狀態:Pending(進行中)、Resolved(已完成,又稱Fulfilled)和Rejected(已失敗)。網絡
Promise是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。dom
ES6規定,Promise對象是一個構造函數,用來生成Promise實例:ecmascript
var promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操做成功 */){ resolve(value); } else { reject(error); } });
resolve:在異步操做成功時調用,並將異步操做的結果,做爲參數傳遞出去;
reject:在異步操做失敗時調用,並將異步操做報出的錯誤,做爲參數傳遞出去;
Promise實例生成之後,能夠用then方法、catch方法分別指定Resolved狀態和Rejected狀態的回調函數:
// Promise測試(then、catch) new Promise(function(resolve,reject) { let num = Math.random() * 2; console.log("產生的隨機數爲:" + num); setTimeout(function () { if(num < 1) { console.log("即將執行成功"); resolve("200 OK"); } else { console.log("即將執行失敗"); reject("失敗的緣由是num爲:" + num); } }, num * 1000); }).then(function(r) { console.log("then:" + r); }).catch(function(j) { console.log("catch:" + j); });
PS:只用then也能夠代替上述效果,由於then能夠接受兩個回調函數做爲參數,第二個參數可選。第一個回調函數是Promise對象的狀態變爲Resolved時調用,第二個回調函數是Promise對象的狀態變爲Rejected時調用:
promise.then(function(value) { // success }, function(error) { // failure });
鏈式多任務串行
有若干個異步任務,須要先作任務1,若是成功後再作任務2,任何任務失敗則再也不繼續並執行錯誤處理函數。要串行執行這樣的異步任務,不用Promise須要寫一層一層的嵌套代碼,而使用Promise則能夠採用鏈式寫法:job1.then(job2).then(job3).catch(handleError)
// Promise測試(多任務串行執行) var p = new Promise(function (resolve, reject) { console.log("resolve開始"); resolve(8); }); function multi(param) { return new Promise(function(resolve, reject) { console.log("計算" + param + "*" + param + ":"); setTimeout(resolve, 1500, param * param); }); }; function add(param) { return new Promise(function(resolve, reject) { console.log("計算" + param + "+" + param + ":"); setTimeout(resolve, 1500, param + param); }); }; p.then(multi).then(add).then(multi).then(function(param){ console.log("獲得最終的值爲:" + param); });
Promise.all()實現多任務並行
一個頁面聊天系統,咱們須要從兩個不一樣的URL分別得到用戶的我的信息和好友列表,這兩個任務是須要並行執行的,用Promise.all()實現以下:
var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, 'P1'); }); var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, 'P2'); }); // 同時執行p1和p2,並在它們都完成後執行then: Promise.all([p1, p2]).then(function (results) { console.log(results); // 得到一個Array: ['P1', 'P2'] });
Promise.race()實現多任務賽跑
有些時候,多個異步任務是爲了容錯。好比,同時向兩個URL讀取用戶的我的信息,只須要得到先返回的結果便可,其餘任務的結果會被丟棄。這種狀況下,用Promise.race()實現:
var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, 'P1'); }); var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, 'P2'); }); Promise.race([p1, p2]).then(function (result) { console.log(result); // 'P1' });
參考資料
Promise:https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544
ECMAScript 6 Promise對象:https://www.w3cschool.cn/ecmascript/3uge1q5v.html