手写promise
。
现代浏览器支持已经支持了promise,下面我用Cpromise类来重新写一个promise,探索一下promise实现的原理:
直接上代码:
/* Cpromise:构造函数 excutor:内部同步执行函数 (resolve,reject) => {} */ function Cpromise (excutor){ this.state = 'pendding';//promise状态 this.value = undefined;//正产返回值 this.reason = undefined;//异常返回值 this.resolveCallbacks = [];//正常状态回调队列 this.rejectedCallbacks = [];//异常状态回调队列 let resolve = value => {//正常执行函数 // console.log(this.state,"resolve函数执行"); if(this.state === 'pendding'){ this.state = 'fulfilled';//promise状态变为正常状态 this.value = value;//拿到正常返回值 this.resolveCallbacks.forEach( fn => fn());//执行正常回调队列中的方法 } }; let reject = reason =>{//异常执行函数 // console.log(this.state,"reject函数执行"); if(this.state === 'pendding'){ this.state = "rejected";//promise状态变为异常 this.reason = reason;//拿到异常返回值 this.rejectedCallbacks.forEach( fn => fn() );//执行异常回调队列里的方法 } } try{ // console.log("开始执行excutor函数"); excutor(resolve,reject);//同步执行函数 }catch(err){ reject(err); } } Cpromise.prototype.then = function(onFulfilled,onRejected){ // promise的then方法返回一个promise对象 // console.log("执行then方法"); onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;//设置then方法的默认正常回调 onRejected = typeof onRejected === 'function' ? onRejected : err => {throw err};//设置then方法的默认异常回调 let cpromise2 = new Cpromise((resolve,reject) => { if(this.state === 'fulfilled'){//then方法执行时,promise返回正常值时,直接执行then的正常回调 // console.log("onFulfilled方法执行"); setTimeout(() => { try { let x = onFulfilled(this.value);//执行then中的正常回调 resolvePromise(cpromise2,x,resolve,reject);//执行resolve } catch (e) { reject(e) } },0) } if(this.state === 'rejected'){//then方法执行时,promise返回异常值时,直接执行then的异常回调 // console.log("onRejected方法执行"); setTimeout(() => { try { let x = onRejected(this.reason);//执行then中的异常回调 resolvePromise(cpromise2,x,resolve,reject);//执行resolve } catch (e) { reject(e) } },0) } if(this.state === 'pendding'){//then方法执行时,同步函数体中的resolve或reject还没执行时,把then内的正常回调和异常回调放到各自的队列中,等待执行 // console.log("向正常|异常回调队列添加回调"); this.resolveCallbacks.push(() => { setTimeout(() => { try { let x = onFulfilled(this.value);//执行then中的正常回调 resolvePromise(cpromise2,x,resolve,reject);//执行resolve } catch (e) { reject(e); } },0) }); this.rejectedCallbacks.push(() => { setTimeout(() => { try { let x = onRejected(this.reason);//执行then中的异常回调 resolvePromise(cpromise2,x,resolve,reject);//执行resolve } catch (e) { reject(e); } },0) }) } }); return cpromise2; } function resolvePromise(promise2,x,resolve,reject){//把正常|异常值放到 then方法返回出去的promise的返回值中 if( x === promise2 ){ return reject(new TypeError('Chaining cycle detected for promise')); } let called; if(x != null && (typeof x === 'object' || typeof x === 'function')){ try { let then = x.then; if(typeof then === 'function'){//如果x是promise对象 就采用x这个promise对象的结果 then.call(x,y => { if(called) return; called = true; resolvePromise(promise2, y, resolve, reject);//递归一下 y有可能还是promise对象 then方法内的promise对象都返回结果后,将结果返回给最外层的then的promise对象,然后返回(resolve|reject)出去 },err => { if(called) return; called = true; reject(err); }) }else{//如果不是promise 返回x resolve(x); } } catch (e) { if(called)return; called = true; reject(e); } }else{//如果不是函数 返回 x resolve(x); } } // catch方法 then方法的语法糖 Cpromise.prototype.catch = function(callback){ return this.then(null,callback); } // resolve方法 Cpromise.resolve = function(val){ return new Cpromise((resolve,reject) => { resolve(val); }) } // reject方法 Cpromise.reject = function(val){ return new Cpromise((resolve,reject) => { reject(val); }) } // race方法 Cpromise.race = function(promises){ return new Cpromise((resolve,reject) => { for(let i = 0;i < promises.length;i++){ promises[i].then(resolve,reject);//谁先执行完,就返回谁 } }) } // all方法 Cpromise.all = function(promises){ let arr = []; let i = 0; function processData(index,data,resolve){ arr[index] = data; i++; if(i === promises.length){ resolve(arr); } } return new Cpromise((resolve,reject) => { for(let i = 0;i < promises.length;i++){ promises[i].then(data => { processData(i,data,resolve); },reject); } }) } // 测试 let p = new Cpromise((resolve,reject) => { let random = Math.floor(Math.random()*10); if(random > 5){ resolve(random) }else{ reject(random) } }) p.then(data => { console.log(data,"resolve"); }).catch(err => { console.log(err,"catch"); }) let p1 = new Cpromise((resolve,reject) => { setTimeout(() => { resolve(1000); },1000) }) let p2 = new Cpromise((resolve,reject) => { setTimeout(() => { resolve(2000); },2000) }) let pAll = Cpromise.all([p1,p2]).then(result => { console.log(result,"all"); }) let pRace = Cpromise.race([p1,p2]).then(result => { console.log(result,"race"); }) let pResolve = Cpromise.resolve("resolve"); pResolve.then(data => { console.log(data,"resolve"); }) let pReject = Cpromise.reject("reject"); pReject.then(data => { console.log(data); },err => { console.log(err,"reject"); })
测试了一下,可以正常使用,
说以下自己的大致理解:
promise,主要把异步函数变成同步执行,避免了回调地狱
原理其实还是用了回调函数,
promise类内部有
状态变量 state 3个状态:pendding(正在执行)、fulfilled(正常返回)、rejected(异常返回)
正常返回值变量:value
异常返回值:reason
正常返回回调 resolve
异常返回回调 reject
正常回调队列 resolveCallbacks
异常回调队列 rejectCallbacks
promise接收一个同步执行函数参数 excutor,实例化时执行此函数,执行时会把内部的resolve和reject函数作为参数传到excutor内;
当excutor函数执行,状态冲pendding--->fulfilled 或 pendding --->rejected 时,分别执行 resolve和reject,从而将返回值传到then方法内
函数执行顺序excutor、then
当excutor内部不是异步函数时,then方法执行时,promise的状态已经变成了fullfilled或rejected,then方法就会直接执行then方法的正常回调或异常回调
如果excutor是异步函数,then方法执行时,promise状态是pendding状态,这时,then方法会把then的两个回调分别放到promise内部的正常回调队列和异常回调队列中,等待excutor内部resolve或reject的执行,这两个方法会做如下事情:将状态改成成功或失败状态,将正常返回值赋值给value变量,或者把异常原因返回给reason,然后,执行对应队列中的方法。
另外.then方法是可以链式调用的,需要then返回的是一个promise对象,假如then里的两个回调参数也是返回的promise对象,这里就需要做一些处理
then方法会把then回调函数执行后得到的值,传给then本身的promise作为返回值,如果then内部是promise则,需要把回调函数promise的返回值传给then本身的promise的返回值,这样才是正常的。
所以有一个resolvePromise函数,这里判断then内的回调是不是promise对象,如果是,则拿到then回到函数promise的返回值后再通过then本身的promise的resolve将值返回出去,如果then的回调不是promise对象,则直接把回调函数的返回值或一个基础值作为返回值传给then本身的promise。总结一下,then本身的promise要从回调内拿到返回值,二者个回调有可能是一个函数的返回值,也有可能是一个promise对象的返回值,也有可能是多个promise嵌套的返回值。具体处理看上诉代码。
。