1.首先申明Promise , promise 是一个类,接收一个函数作为参数,函数中会接收两个参数,一个是成功的回调 resolve,一个是失败的回调 reject, 在new 该类的的时候,传入的函数会立即执行
1 class Promise { 2 constructor(task){ 3 let resolve = () => { 4 5 } 6 let reject = () => { 7 8 } 9 task(resolve,reject) 10 } 11 }
2.解决基本状态,promise有三个状态 pending, fulfilled, rejected
pending为初始态,可以转为 fulfilled 成功态 也可以转为 rejected 失败态
fulfilled 成功态 不可以转为其他状态 并且有一个返回值 value
rejected 失败态 不可以转为其他状态 并且有一个错误返回值 reason
如果任务函数报错 直接执行 reject
1 class Promise2 { 2 constructor(task){ 3 this.status = 'pending' 4 this.value = undefined 5 this.reason = undefined 6 let resolve = value => { 7 if(this.status === 'pending'){ 8 this.status = 'fulfilled' 9 this.value = value 10 } 11 } 12 let reject = reason => { 13 if(this.status === 'pending'){ 14 this.status = 'rejected' 15 this.reason = reason 16 } 17 } 18 try{ 19 task(resolve,reject) 20 }catch(err){ 21 reject(err) 22 } 23 } 24 }
3.then方法
在promise 中有个then 的方法,里面有两个参数 onFulfilled,onRejected,成功有成功的值 失败有失败的原因
当状态值是 fulfilled 的时候 执行 onFulfilled 函数并传入 this.value .当状态值是rejected 的时候 执行onRejected 函数并且传入this.reason
如果 onFulfilled onRejected 是函数,必须在 fulfilled 和 rejected 后调用 并且第一个参数 分别是 this.value 和 this.reason
1 class Promise2 { 2 constructor(task){ 3 this.status = 'pending' 4 this.value = undefined 5 this.reason = undefined 6 let resolve = value => { 7 if(this.status === 'pending'){ 8 this.status = 'fulfilled' 9 this.value = value 10 } 11 } 12 let reject = reason => { 13 if(this.status === 'pending'){ 14 this.status = 'rejected' 15 this.reason = reason 16 } 17 } 18 try{ 19 task(resolve,reject) 20 }catch(err){ 21 reject(err) 22 } 23 } 24 then(onFulfilled,onRejected){ 25 if(this.status === 'fulfilled'){ 26 onFulfilled(this.value) 27 } 28 if(this.status === 'rejected'){ 29 onRejected(this.reason) 30 } 31 } 32 }
4.解决异步的问题
上面基本可以解决一些同步的代码,但是当resolve 在setTimeout 中执行的时候,then 的时候的status 还是pending 状态,那么我们需要在then 的时候将成功和失败的函数存起来,在resolve 或者reject 的时候去调用
类似于发布订阅模式 先将函数存在起来 而且可能会有多个then 函数 所有将成功和失败的函数分别存在 两个数组中 成功或者失败的时候用forEach 去调用
1 class Promise2 { 2 constructor(task){ 3 this.status = 'pending' 4 this.value = undefined 5 this.reason = undefined 6 // 成功的回调函数存放数组 7 this.onFulfilledCallbacks = [] 8 // 失败的函数回调存放数组 9 this.onRejectedCallbacks = [] 10 let resolve = value => { 11 if(this.status === 'pending'){ 12 this.status = 'fulfilled' 13 this.value = value; 14 // resolve 执行后调用成功回调函数 15 this.onFulfilledCallbacks.forEach(fn => fn()) 16 } 17 } 18 let reject = reason => { 19 if(this.status === 'pending'){ 20 this.status = 'rejected' 21 this.reason = reason 22 // reject 执行后调用失败回调函数 23 this.onRejectedCallbacks.forEach(fn => fn()) 24 } 25 } 26 try{ 27 task(resolve,reject) 28 }catch(err){ 29 reject(err) 30 } 31 } 32 then(onFulfilled,onRejected){ 33 if(this.status === 'fulfilled'){ 34 onFulfilled(this.value) 35 } 36 if(this.status === 'rejected'){ 37 onRejected(this.reason) 38 } 39 if (this.status === 'pending'){ 40 this.onFulfilledCallbacks.push(onFulfilled(this.value)) 41 this.onRejectedCallbacks.push(onRejected(this.reason)) 42 } 43 } 44 }
5.解决链式调用的问题
我们常常这样用 new Promise().then().then() 来解决回调地狱的问题
1.为了达成链式调用 在then 函数中返回 一个新的promise,我们这叫 promise2 = new Promise(function(resolve,reject){})
2.将promise2 中的返回值传递给后面的then方法
3.如果返回的是一个普通值 也传递给后面的then 方法中
4.按规范 onFulfilled() 或者 onRejected()即第一个then 的返回值 我们叫 x ,判断x 的函数我们叫 resolvePromise
在resolvePromise 中首先要看x 是不是Promise
如果是Promise 就取他的结果 作为新的promise2 的成功的结果
如果是成功的值 直接作为promise2 的成功的结果
resolevePromise 的参数有 promise2 这个是默认返回的promise x 是我们自己返回的对象 还要 resolve,reject 是promise2 的
1 class Promise2 { 2 constructor(task){ 3 this.status = 'pending' 4 this.value = undefined 5 this.reason = undefined 6 // 成功的回调函数存放数组 7 this.onFulfilledCallbacks = [] 8 // 失败的函数回调存放数组 9 this.onRejectedCallbacks = [] 10 let resolve = value => { 11 if(this.status === 'pending'){ 12 this.status = 'fulfilled' 13 this.value = value; 14 // resolve 执行后调用成功回调函数 15 this.onFulfilledCallbacks.forEach(fn => fn()) 16 } 17 } 18 let reject = reason => { 19 if(this.status === 'pending'){ 20 this.status = 'rejected' 21 this.reason = reason 22 // reject 执行后调用失败回调函数 23 this.onRejectedCallbacks.forEach(fn => fn()) 24 } 25 } 26 try{ 27 task(resolve,reject) 28 }catch(err){ 29 reject(err) 30 } 31 } 32 then(onFulfilled,onRejected){ 33 let promise2 = new Promise2((resolve,reject) =>{ 34 if(this.status === 'fulfilled'){ 35 let x = onFulfilled(this.value) 36 resolvePromise(promise2,x,resolve,reject) 37 } 38 if(this.status === 'rejected'){ 39 let x = onRejected(this.reason) 40 resolvePromise(promise2,x,resolve,reject) 41 } 42 if (this.status === 'pending'){ 43 this.onFulfilledCallbacks.push(() =>{ 44 let x = onFulfilled(this.value) 45 resolvePromise(promise2,x,resolve,reject) 46 }) 47 this.onRejectedCallbacks.push(() => { 48 let x = onRejected(this.reason) 49 resolvePromise(promise2,x,resolve,reject) 50 }) 51 } 52 }) 53 return promise2 54 55 } 56 }
6.我们在来完成 resolvePromise 函数
让不同的promise代码互相套用,叫做resolvePromise
-
如果 x === promise2,则是会造成循环引用,自己等待自己完成,则报“循环引用”错误
比如
1 let p = new Promsie((resolve) => { 2 resolve(0) 3 }) 4 let p2 = p.then(data => { 5 return p2 6 )
先判断x
如果 if x is an object or function,Let then be x.then
x不能是 null
x是普通值 直接 resolve(x)
x是对象或者函数的时候 let then = x.then
如果取then 报错 直接走 reject()
如果then是个函数,则用call执行then,第一个参数是this,后面是成功的回调和失败的回调
如果成功的回调还是pormise,就递归继续解析
成功和失败只能调用一个 所以设定一个called来防止多次调用
function resolvePromise(promise2, x, resolve, reject){ // 循环引用报错 if(x === promise2){ // reject报错 return reject(new TypeError('Chaining cycle detected for promise')); } // 防止多次调用 let called; // x不是null 且x是对象或者函数 if (x != null && (typeof x === 'object' || typeof x === 'function')) { try { // A+规定,声明then = x的then方法 let then = x.then; // 如果then是函数,就默认是promise了 if (typeof then === 'function') { // 就让then执行 第一个参数是this 后面是成功的回调 和 失败的回调 then.call(x, y => { // 成功和失败只能调用一个 if (called) return; called = true; // resolve的结果依旧是promise 那就继续解析 resolvePromise(promise2, y, resolve, reject); }, err => { // 成功和失败只能调用一个 if (called) return; called = true; reject(err);// 失败了就失败了 }) } else { resolve(x); // 直接成功即可 } } catch (e) { // 也属于失败 if (called) return; called = true; // 取then出错了那就不要在继续执行了 reject(e); } } else { resolve(x); } }