Promise 解析
Promise
由于js的語言特性(用戶交互)和工作環(huán)境(瀏覽器腳本),決定了它是單線程工作,所以兩段腳本不能同時運行,但為了實現(xiàn)功能,所以人們使用了事件和回調(diào)來初步解決這個問題,例如(addEventListener),但這也帶來了嚴重的回調(diào)問題,非常容易陷入回調(diào)地獄的困惱,
由于這個問題。js發(fā)展至今,社區(qū)提出了promise(承若)標準,被es6寫入了語言標準中,統(tǒng)一了它的用法,并在原生中提供了標準的Promise對象
讓我們先來實例化一個標準的promise對象:
//實例化一個promise對象,這個對象有兩個參數(shù)(resolve-決定,reject-拒絕)let promise = new Promise((resolve,reject)=>{//延時3s,把promise的狀態(tài)改為resolve-決定setTimeout(function(){resolve('666')},3000)})//每個實例都有then()方法,用來獲取其值或原因。//then(onFulfilled, onRejected)//成功的回調(diào),失敗的回調(diào)promise.then(data=>{console.log(data)},err=>{console.error(err)}).then()同時promise還可以多次調(diào)用then()方法,也可以在resolve中繼續(xù)拋出一個新的promise 例:
promise.then(function(data){console.log('data2=',data);},function(err){console.log('err2=',err);});或者:
let promise2 = promise.then(function(data){return new Promise(function(resolve,reject){setTimeout(function(){resolve(data + '777' );},1000);});});當然還有常見的all(),catch(),resolve(),reject()等等一些方法,而這些方法都是按照Promise/A+規(guī)范規(guī)定的 (詳情)
我們現(xiàn)在就按照這個規(guī)范來實現(xiàn)一個屬于我們自己的promise
首先我們先定義出這個類:
// executor是一個執(zhí)行函數(shù),在實例化的時候被傳入。這個函數(shù)會執(zhí)行兩個被傳入的狀態(tài)函數(shù) var Promise = function (executor) { let self = this;//沒個promise都會有個初始化值,這個值在規(guī)范中叫做pendingself.status = 'pending';self.value = undefined; // 默認成功的值self.reason = undefined; // 默認失敗的原因self.onResolvedCallbacks = []; // 存放then成功的回調(diào)self.onRejectedCallbacks = []; // 存放then失敗的回調(diào)// 成功狀態(tài)要執(zhí)行的函數(shù)function resolve(value) {//更改他的狀態(tài)值,為成功,且不能更改if (self.status === 'pending') {self.status = 'resolved';self.value = value;//實例多次調(diào)用then(),循環(huán)釋放數(shù)組self.onResolvedCallbacks.forEach(function (fn) {fn();});}}// 失敗狀態(tài)要執(zhí)行的函數(shù)function reject(reason) {//更改他的狀態(tài)值,為失敗,且不能更改if (self.status === 'pending') {self.status = 'rejected';self.reason = reason;//實例多次調(diào)用then(),循環(huán)釋放數(shù)組self.onRejectedCallbacks.forEach(function (fn) {fn();})}}如果直接傳入錯誤的代碼,那么直接進入rejecttry {executor(resolve, reject)} catch (e) {// 捕獲的時候發(fā)生異常,就直接失敗了reject(e);} }下面我們來實現(xiàn)then()方法,個方法每個實例都有,他是一個方法,所以我們把它掛載到Promise原型上:
Promise.prototype.then = function (onFulfilled, onRjected) {//成功和失敗默認一個函數(shù),防止報錯,onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {return value;}onRjected = typeof onRjected === 'function' ? onRjected : function (err) {throw err;}let self = this;//定義一個返回的promiselet promise2;//當狀態(tài)是成功的時候,可能會在函數(shù)中再次返回一個promiseif (self.status === 'resolved') {promise2 = new Promise(function (resolve, reject) {// 當成功或者失敗執(zhí)行時有異常那么返回的promise應(yīng)該處于失敗狀態(tài)//這個x 是第一個promise執(zhí)行后的結(jié)果// x可能是一個promise 也有可能是一個普通的值setTimeout(function () {try {let x = onFulfilled(self.value);// x可能是別人promise,寫一個方法統(tǒng)一處理resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})})}//當狀態(tài)是失敗的時候if (self.status === 'rejected') {promise2 = new Promise(function (resolve, reject) {setTimeout(function () {try {let x = onRjected(self.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})})}// 當調(diào)用then時可能沒成功 也沒失敗if (self.status === 'pending') {promise2 = new Promise(function (resolve, reject) {// 此時沒有resolve 也沒有rejectself.onResolvedCallbacks.push(function () {setTimeout(function () {try {let x = onFulfilled(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}})});self.onRejectedCallbacks.push(function () {setTimeout(function () {try {let x = onRjected(self.reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})});})}return promise2; }集中處理x
function resolvePromise(promise2, x, resolve, reject) {// 有可能這里返回的x是別人的promise// 先跑錯if (promise2 === x) { //這里應(yīng)該報一個類型錯誤,有問題return reject(new TypeError('循環(huán)引用了'))}// 看x是不是一個promise,promise應(yīng)該是一個對象let called; // 表示是否調(diào)用過成功或者失敗if (x !== null && (typeof x === 'object' || typeof x === 'function')) {//根據(jù)語法規(guī)定的幾種情況來判斷// 可能是promise {},看這個對象中是否有then方法,如果有then我就認為他是promise了try {let then = x.then;if (typeof then === 'function') {// 成功then.call(x, function (y) {if (called) returncalled = true// y可能還是一個promise,在去解析直到返回的是一個普通值//遞歸調(diào)用這個函數(shù),resolvePromise(promise2, y, resolve, reject)}, function (err) { //失敗if (called) returncalled = truereject(err);})} else {resolve(x)}} catch (e) {if (called) returncalled = true;reject(e);}} else { // 說明是一個普通值1resolve(x); // 表示成功了} }在實現(xiàn)了這些之后,其他的方法,更多的就是一個語法糖,我們來實現(xiàn)他們
catch:
all
//會傳入一個數(shù)組,這個數(shù)組是promise集合 Promise.all = function (promises) {return new Promise(function (resolve, reject) {//arr是最終返回值的結(jié)果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)}}) }race
//race就是賽跑的意思,誰獲取結(jié)果比較快,就返回誰 // 只要有一個promise成功了 就算成功。如果第一個失敗了就失敗了 Promise.race = function (promises) {return new Promise(function (resolve, reject) {for (var i = 0; i < promises.length; i++) {promises[i].then(resolve,reject)}}) } // 生成一個成功的promise Promise.resolve = function(value){return new Promise(function(resolve,reject){resolve(value);}) } // 生成一個失敗的promise Promise.reject = function(reason){return new Promise(function(resolve,reject){reject(reason);}) }defer 延期處理
會包容promise 可用于封裝在傳遞方法之外調(diào)用原有的promise回調(diào)
轉(zhuǎn)載于:https://www.cnblogs.com/oicb/p/10568151.html
總結(jié)
以上是生活随笔為你收集整理的Promise 解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫(3)
- 下一篇: Hive常用函数大全一览