從事前端的朋友或多或少的接觸過Promise,當代碼中回調函數層級過多你就會發現Promise異步編程的魅力,相信此文必定能幫你排憂解惑!
Promise是JS異步編程中的重要概念,異步抽象處理對象,是目前比較流行Javascript異步編程解決方案之一
或許是筆者理解能力有限,對官方術語怎麼也感覺不到親切,下面我來用通俗易懂的語言解釋下:
Promise是一個包含三種狀態的對象(pending、fulfilled、rejected),能夠鏈式的處理異步請求(then方法)並能很好地處理異常問題,是解決回調地獄的良好方案之一。
回調函數處理多層異步示例
$.ajax({ url: url1, success: function(rsp){ $.ajax({ url: url2, success: function(rsp){ $.ajax({ url: url3, success: function(rsp){ //do sth }, error: function(error){ } }); }, error: function(error){ } }); }, error: function(error){ } });
將promise封裝在$.ajax中
$.ajax = function(config){ return new Promise(function(resolve, reject){ //1省略... xmlhttp.onreadystatechange = function(){ if(xmlhttp.status==200){ resolve(rspData); }else{ reject(xmlhttp.statusText); } }; //2省略... }) } $.ajax({url: url1}).then(function(val){ return $.ajax({url: val.url}) }).then(function(val){ return $.ajax({url: val.url}) }).catch(function(err){ console.log(err); }}
封裝好的Promise處理異步可讀性可維護性以及代碼美觀度不言而喻
//pending狀態的promise var promise = new Promise(function(resolve, reject){ //do sth }) //fulfilled狀態的promise var promise = Promise.resolve(1).then(function resolve(value){console.log(value)}); // var promise = new Promise(function(resolve){resolve(1)}) //rejected狀態的promise var promise = Promise.reject(new Error('error')).catch(function(error){console.error(error)}); // var promise = new Promise(function(resolve,reject){resolve(new Error('error'))})
Promise#then
promise.then(onFulfilled, onRejected)
返回一個新的promise。這裏常常會有一個疑問:爲何不返回原來的promise,我的是這樣認爲的,若返回同一個promise則狀態不一致,promise規範說明當pending至fulfilled/rejected時狀態肯定後不能再改變。
Promise#catch promise.catch(function(error){ throw new Error(error); })
注意:IE8及如下版本會出現 identifier not found 的語法錯誤,可將點標記法改成中括號標記法
promise['catch'](function(error){ throw new Error(error); })
rejected狀態的promise拋出異常
至關於
promise.then(undefined, onRejected)
then & catch 結合示例
promise.then(function f1(value){ //do sth 1 }).then(function f2(value){ //do sth 2 }).then(function f3(value){ //do sth 3 }).catch(function(error){ console.log(error); })
promise.finally(onFinally)
返回一個Promise,在promise執行結束時,不管結果是fulfilled或者是rejected,在執行then()和catch()後,都會執行
promise.all([promise1, promise2, promise3]).then(resolve);
示例
// `delay`毫秒後執行resolve function timerPromisefy(delay) { return new Promise(function (resolve) { setTimeout(function () { resolve(delay); }, delay); }); } var startDate = Date.now(); // 全部promise變爲resolve後程序退出 Promise.all([ timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128) ]).then(function (values) { console.log(Date.now() - startDate + 'ms'); // 約128ms console.log(values); // [1,32,64,128] });
在接收到全部的對象promise都變爲 FulFilled 返回一個resolve(array),或者 某一個promise對象變成Rejected 狀態返回resolve(err)
傳遞給 Promise.all 的promise並非一個個的順序執行的,而是同時開始、並行執行的。
promise.race([promise1, promise2]).then(resolve, reject)
示例
// `delay`毫秒後執行resolve function timerPromisefy(delay) { return new Promise(function (resolve) { setTimeout(function () { resolve(delay); }, delay); }); } // 任何一個promise變爲resolve或reject 的話程序就中止運行 Promise.race([ timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128) ]).then(function (value) { console.log(value); // => 1 });
只要有一個promise對象進入 FulFilled 或者 Rejected 狀態的話,就會繼續進行後面的處理。
學習完Promise後,一定要重寫Promise,後續遇到瀏覽器環境不支持也可有的放矢
代碼以下
/** * @author chenchangyuan * @date 2019-02-23 * */ function Promise(executor){ if(typeof executor !== 'function'){ throw new Error('executor is not a function'); } var self = this; self.state = 'pending';//pending fulfilled rejected self.value = null; self.reason = null; self.callbackResolveFn = []; self.callbackRejectFn = []; function resolve(value){ if(self.state === 'pending'){ self.state = 'fulfilled'; self.value = value; self.callbackResolveFn.forEach(function(fn){ fn(); }); } } function reject(reason){ if(self.state === 'pending'){ self.state = 'rejected'; self.reason = reason; self.callbackRejectFn.forEach(function(fn){ fn(); }); } } try{ executor(resolve, reject); }catch(err){ reject(err); } } //回溯函數 function resolvePromise(promise, x, resolve, reject){ if(promise === x) return reject(new TypeError('循環引用')); var flag = false; if(x !== null && (typeof x === 'object' || typeof x === 'function')){ try{ var then = x.then; if(typeof then === 'function'){ then.call(x, function(val){ if(flag) return; flag = true; resolvePromise(promise, val, resolve, reject); }, function(err){ if(flag) return; flag = true; reject(err); }); }else{ resolve(x); } } catch(err){ if(flag) return; flag = true; reject(err); } }else{ resolve(x); } } //返回一個新的promise(pending:push(fn),fulfilled:resolve(val),rejected:reject(reason)) Promise.prototype.then = function(onFulfilled, onRejected){ onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){ return value; }; onRejected = typeof onRejected === 'function' ? onRejected : function(err){ throw new Error(err); }; var self = this, promise2; if(self.state === 'fulfilled'){ promise2 = new Promise(function(resolve, reject){ setTimeout(function(){ try{ //將x處理成一個原始值 var x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch(e){ reject(e); } }) }) } if(self.state === 'rejected'){ promise2 = new Promise(function(resolve, reject){ setTimeout(function(){ try{ //將x處理成一個原始值 var x = onRejected(self.reason); resolvePromise(promise2, x, resolve, reject); } catch(e){ reject(e); } }) }) } if(self.state === 'pending'){ promise2 = new Promise(function(resolve, reject){ self.callbackResolveFn.push(function(){ setTimeout(function(){ try{ //將x處理成一個原始值 var x = onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); } catch(e){ reject(e); } }) }); self.callbackRejectFn.push(function(){ setTimeout(function(){ try{ //將x處理成一個原始值 var x = onRejected(self.reason); resolvePromise(promise2, x, resolve, reject); } catch(e){ reject(e); } }) }); }) } return promise2; } Promise.prototype['catch']= function (callback) { return this.then(undefined, callback) } Promise.all = function (promises) { return new Promise(function (resolve, reject) { let arr = []; let i = 0; function processData(index, y) { arr[index] = y; if (++i === promises.length) { resolve(arr); } } for (let i = 0; i < promises.length; i++) { promises[i].then(function (y) { processData(i, y) }, reject) } }) } Promise.race = function (promises) { return new Promise(function (resolve, reject) { for (var i = 0; i < promises.length; i++) { promises[i].then(resolve,reject) } }); } Promise.resolve = function(value){ return new Promise(function(resolve,reject){ resolve(value); }); } Promise.reject = function(reason){ return new Promise(function(resolve,reject){ reject(reason); }); } Promise.defer = Promise.deferred = function () { var d = {}; d.promise = new Promise(function (resolve, reject) { d.resolve = resolve; d.reject = reject; }); return d } module.exports = Promise;
因爲是參(抄)考(襲)前輩的polyfill,本身編碼測試時出現了兩處錯誤,ES6 Promise 規範的2.3.1和2.3.4前端
2.3.1git
2.3.4
通過改正測試成功
大家的支持是我最大的動力,熬夜碼字不易,若是此文對你有幫助,請不吝star--->https://github.com/chenchangyuan/promisegithub
有興趣加筆者好友的同窗請掃描下方二維碼(1.本人微信,2.微信公衆號,3.技術交流微信羣),願與您成爲好友共同探討技術,暢聊生活!ajax