You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functionMyPromise(fn){this.status='pending'this.val=''this.error=''this.fulfilledList=[]this.rejectedList=[]constresolve=(params)=>{// 注意 this ,如果不暂存 this,就要用箭头函数if(this.status==='pending'){this.status='fulfilled'this.val=params}}constreject=(error)=>{if(this.status==='pending'){this.status='rejected'this.error=error}}fn(resolve,reject)}MyPromise.prototype.then=function(fulfilledFn,rejectedFn){if(this.status==='fulfilled'){fulfilledFn(this.val)}if(this.status==='rejected'){rejectedFn(this.error)}}newMyPromise((resolve,reject)=>{resolve(1)}).then((data)=>{console.log(data)},(err)=>{console.log(err)})
2. 支持异步版
functionMyPromise(fn){this.status='pending'this.val=''this.error=''this.fulfilledList=[]this.rejectedList=[]constresolve=(params)=>{// 注意 this ,如果不暂存 this,就要用箭头函数if(this.status==='pending'){this.status='fulfilled'this.val=paramsthis.fulfilledList.forEach((fn)=>{fn(this.val)})}}constreject=(error)=>{if(this.status==='pending'){this.status='rejected'this.error=errorthis.rejectedList.forEach((fn)=>{fn(this.error)})}}fn(resolve,reject)}MyPromise.prototype.then=function(fulfilledFn,rejectedFn){if(this.status==='fulfilled'){fulfilledFn(this.val)}if(this.status==='rejected'){rejectedFn(this.error)}if(this.status==='pending'){this.fulfilledList.push(fulfilledFn)this.rejectedList.push(rejectedFn)}}newMyPromise((resolve,reject)=>{setTimeout(()=>{resolve(1)},1000)}).then((data)=>{console.log(data)},(err)=>{console.log(err)})
3. 链式调用版
不支持 then 里再返回 Promise 的 版本
functionMyPromise(fn){this.status='pending'this.val=''this.error=''this.fulfilledList=[]this.rejectedList=[]constresolve=(params)=>{// 注意 this ,如果不暂存 this,就要用箭头函数if(this.status==='pending'){this.status='fulfilled'this.val=paramsthis.fulfilledList.forEach((fn)=>{fn(this.val)})}}constreject=(error)=>{if(this.status==='pending'){this.status='rejected'this.error=errorthis.rejectedList.forEach((fn)=>{fn(this.error)})}}fn(resolve,reject)}MyPromise.prototype.then=function(fulfilledFn,rejectedFn){returnnewMyPromise((resolve,reject)=>{// 成功的回调constfulfilledCb=()=>{queueMicrotask(()=>{// 别忘了 then 是微任务, queueMicrotask 在 window 对象上才有try{constres=fulfilledFn(this.val)resolve(res)}catch(err){reject(err)}})}// 错误的回调constrejectedCb=()=>{queueMicrotask(()=>{try{constres=rejectedFn(this.error)// 注意这里,虽然是 rejected 状态,但是回调返回的值,如果不是错误,依然会走 then 的 MyPromise 的resolve(res)}catch(error){reject(error)}})}if(this.status==='fulfilled'){fulfilledCb()}if(this.status==='rejected'){rejectedCb()}if(this.status==='pending'){this.fulfilledList.push(fulfilledCb)this.rejectedList.push(rejectedCb)}})}newMyPromise((resolve,reject)=>{setTimeout(()=>{resolve(1)},1000)}).then((data)=>{console.log(data)return'第一个完成'},(err)=>{console.log(err)}).then((data)=>{console.log(data)})console.log('同步函数')
支持 then 里返回 Promise 的版本
functionMyPromise(fn){this.status='pending'this.val=''this.error=''this.fulfilledList=[]this.rejectedList=[]constresolve=(value)=>{if(valueinstanceofMyPromise){returnvalue.then(resolve,reject)// 细节,适用于 then 里又 return Promise.resolve() 的情况}// 注意 this ,如果不暂存 this,就要用箭头函数if(this.status==='pending'){this.status='fulfilled'this.val=valuethis.fulfilledList.forEach((fn)=>{fn(this.val)})}}constreject=(error)=>{if(this.status==='pending'){this.status='rejected'this.error=errorthis.rejectedList.forEach((fn)=>{fn(this.error)})}}fn(resolve,reject)}MyPromise.prototype.then=function(fulfilledFn,rejectedFn){constthenPromise=newMyPromise((resolve,reject)=>{// 成功的回调constfulfilledCb=()=>{queueMicrotask(()=>{// 别忘了 then 是微任务, queueMicrotask 在 window 对象上才有try{constres=fulfilledFn(this.val)resolvePromise(thenPromise,res,resolve,reject)}catch(err){reject(err)}})}// 错误的回调constrejectedCb=()=>{queueMicrotask(()=>{try{constres=rejectedFn(this.error)// 注意这里,虽然是 rejected 状态,但是回调返回的值,如果不是错误,依然会走 then 的 MyPromise 的resolvePromise(thenPromise,res,resolve,reject)}catch(error){reject(error)}})}if(this.status==='fulfilled'){fulfilledCb()}if(this.status==='rejected'){rejectedCb()}if(this.status==='pending'){this.fulfilledList.push(fulfilledCb)this.rejectedList.push(rejectedCb)}})returnthenPromise}// 处理当 then 里又 return Promise 的情况constresolvePromise=(thenPromise,result,resolve,reject)=>{if(thenPromise===result){returnreject(newTypeError('error due to circular reference'))// 死循环}letcalled// 防止多次调用(这个变量其实不知道是为什么需要的)if(result!==null&&(typeofresult==='object'||typeofresult==='function')){try{constthenable=result.then// 鸭子辨型,如果有 then 属性,就会被认为是 Promiseif(typeofthenable==='function'){thenable.call(result,(data)=>{if(called){return}called=trueresolvePromise(thenPromise,data,resolve,reject)// 返回的可能是一个 Promise 实例或者是一个普通值,所以就递归},(error)=>{if(called){return}called=truereject(error)})}else{resolve(result)}}catch(error){if(called){return}called=true// 防止调用失败后又调用成功reject(error)}}else{// 普通的值, 或者没有resolve(result)}}// -------------------- test --------------------// -------------------- 死循环的例子 --------------------// const promise = new MyPromise((resolve, reject) => {// setTimeout(() => {// resolve('lucas')// }, 2000)// })// promise// .then(// (onfulfilled = (data) => {// console.log(data)// return onfulfilled(data)// })// )// .then((data) => {// console.log(data)// })// -------------------- 需要递归的例子 --------------------constpromise=newMyPromise((resolve,reject)=>{setTimeout(()=>{resolve('lucas')},1000)})promise.then((data)=>{console.log(data)returnnewMyPromise((resolve,reject)=>{setTimeout(()=>{resolve(`${data} next then`)},2000)}).then((data)=>{returnnewMyPromise((resolve,reject)=>{setTimeout(()=>{resolve(`${data} next then`)},2000)})})}).then((data)=>{console.log(data)})
1. 初级版
2. 支持异步版
3. 链式调用版
不支持 then 里再返回 Promise 的 版本
支持 then 里返回 Promise 的版本
4. 支持 Promise 穿透的版本
什么是 Promise穿透:
用 promises-aplus-tests 测试 A+
注意,如果用这个测试,需要把代码里的 queueMicrotask 改成 setTimeout,因为 queueMicrotask 是在 window 上才有的
先全部安装 promises-aplus-tests
然后在
MyPromise
的文件后面加上:最后在命令行执行
promises-aplus-tests ./A+test.js
5. Promise 的各种 API 实现
The text was updated successfully, but these errors were encountered: