js手写一个实现一个简单的promise__小前端chenMr
Posted chengeping
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js手写一个实现一个简单的promise__小前端chenMr相关的知识,希望对你有一定的参考价值。
1.首先来看一下promise常用场景
function chenPromise (arg) return new Promise (resolve, reject) if () doSomeThing(arg) resolve(val) else reject(val)
chenPromise(arg).then(((val) => , (err) =>)
2.了解promise状态
1.常规分三种:PENDING, RESOLVED, REJECTED
2.一开始promise状态是PENDING,当调用了resolve()之后promise的状态就被固定了即成功时的状态RESOLVED,当调用了reject()之后promise状态就被成了REJECTED了
3.上面说了一旦调用了reject()或者resolve()状态就不能被改变了,这一点也可以算是promise的缺陷吧
4.代码是怎么做到状态从pending到resolove就不会被改变了呢可通过代码如下
_resolve()
window.addEventListener(‘message‘, (val)=> if (this.status !== KPromise.PENDING) return // 当状态已经被固定了就不会往下执行了 this.status = KPromise.RESOLVED // 当执行这个函数的时候状态就已经被固定了 this.value = val let handler; while(handler = this.resolveQueues.shift()) handler(this.value) )
3.控制.then()在resolve()后面执行
实现思路:当调用.then(resolvehandle,rejecthandle)方法时将resolvehandle和rejecthandle分别push到一个数组中,当resolve()执行时,遍历两个数组unshift()一次一队列先进先出方式依次执行
then(resolveHandler, rejectHandler) this.resolveQueues.push(resolveHandler) this.rejectQueues.push(rejectHandler)
reject()
let handler;
while(handler = this.rejectQueues.shift()) // 执行以队列方式(先进先出方式)执行被注册函数
handler(this.value)
resolve ()
let handler;
while(handler = this.resolveQueues.shift()) // 执行以队列方式(先进先出方式)执行被注册函数
handler(this.value)
3.实现promise先于setTimeout执行
setTimeout(() => console.log(123), 100) promise().resolve().then(() => console.log(456)) 结果是先输出456 在输出123
这里实现涉及事件循环以及异步任务的宏认为和微任务执行顺序,通过微任务先于宏认为先执行机制来实现,具体可以通过h5新增的messge方法来达到如下
resolve(val)
window.addEventListener(‘message‘, (val)=> // 这里涉及到宏任务和微任务的区别,实现让promises里面的方法是先于setTimeout执行的
if (this.status !== KPromise.PENDING) return // 当状态已经被固定了就不会往下执行了
this.status = KPromise.RESOLVED // 当执行这个函数的时候状态就已经被固定了
this.value = val
let handler;
while(handler = this.resolveQueues.shift()) // 执行以队列方式(先进先出方式)执行被注册函数
handler(this.value)
)
window.postMessage(‘‘) // h5新增
this._finally(this.value)
_rejected(val)
window.addEventListener(‘message‘,()=> // 这里涉及到宏任务和微任务的区别,实现让promises里面的方法是先于setTimeout执行的
this.status = KPromise.REJECTED
let handler;
while(handler = this.rejectQueues.shift()) // 执行以队列方式(先进先出方式)执行被注册函数
handler()
)
window.postMessage(‘‘) // node 中有prosee.nexTick()
this._finally(this.value)
4.实现promise链式调用如promise.then().then()以及实现
then(resolveHandler, rejectHandler) // 实现连续的.then().then().then()调用,通过.then()返回新的promise供后续.then调用 return new KPromise((resolve, reject) => // 外层包装了一层promise function newResolvedHandler(val) if(typeof resolveHandler === ‘function‘) // 判断第一个是否是函数 let result = resolveHandler(val) // 第一参数也就是前一个.then先执行 if(result instanceof KPromise) result.then(resolve, reject) else resolve(result) else resolve(val) function newRejectHandler(val) if (typeof rejectHandler === ‘function‘) let result = rejectHandler(val) // 第二个参数就是前一个.then(,reject())第一reject先执行 if(result instanceof KPromise) result.then(resolve, reject) else reject(result) else reject(val) this.resolveQueues.push(newResolvedHandler) this.rejectQueues.push(newRejectHandler) )
上面所述都是个人认为有坑的地方:下面附上完整代码
class CPromise // 定义三个状态常量 static PENDING = ‘PENDING‘; static RESOLVED = ‘RESOLVED‘; static REJECTED = ‘REJECTED‘; constructor( handler ) if ( typeof handler !== ‘function‘ ) throw new TypeError(‘Promise resolver undefined is not a function‘); this.resolvedQueues = []; // 定义一个空数组,注册保存调用.then(resolve, )方法传递的第一个resolve函数 this.rejectedQueues = []; // 定义一个空数组,注册保存调用.then(, reject)方法传递的二个reject函数 this.finayllyQueues = []; // 定义一个空数组,注册保存调用.finally(finally)这里的finally函数, this.status = CPromise.PENDING; this.value; handler( this._resolve.bind(this), this._reject.bind(this) ); // 通过bind改变当前函数this执行,然后就可以使用this.status,RESOLVED等常量 _resolve(val) // setTimeout(_=> // , 0); window.addEventListener(‘message‘, _=> // message是h5的新特性,这里涉及到异步中的宏认为和微任务执行优先级,这里message事件属于微任务优先于setTimeout执行,例如下面的demo // setTimeout(() => console.log(123), 0) // CPromise.resolve().then((res)=>console.log(456)) // 上面代码先输出456然后输出123 if (this.status !== CPromise.PENDING) return; // 这里的判断是防止当状态是resolved或者是rejected也就是状态被固定时状态被改变 // console.log(‘_resolve‘); this.status = CPromise.RESOLVED; // 将状态置位resolve 并且不允许改变 this.value = val; let handler; while( handler = this.resolvedQueues.shift() ) // 执行以队列方式(先进先出方式)执行被注册函数 handler(this.value); // 执行.then里面第一参数即resolve方法 this._finally(this.value); // 最后执行finally方法 ); window.postMessage(‘‘); // 触发上面的message事件 _reject(val) // setTimeout(_=> // , 0); window.addEventListener(‘message‘, _=> if (this.status !== CPromise.PENDING) return; // 这里的判断是防止当状态是resolved或者是rejected也就是状态被固定时状态被改变 this.status = CPromise.REJECTED; // 将状态置位rejected 并且不允许改变 this.value = val; let handler; while( handler = this.rejectedQueues.shift() ) // 执行以队列方式(先进先出方式)执行被注册函数 handler(this.value); // 调用.then里面第二个参数即rejected方法 this._finally(this.value); // 最后执行finally方法 ); window.postMessage(‘‘); _finally() // 通过此方法触发在finally方法注册的finayllyQueues数组里面的所有方法 window.addEventListener(‘message‘, _=> this.status = CPromise.REJECTED; let handler; while( handler = this.finayllyQueues.shift() ) // 执行以队列方式(先进先出方式)执行被注册函数 handler(this.value); ); window.postMessage(‘‘); then( resolvedHandler, rejectedHandler ) return new CPromise( (resolve, reject) => // 这里返回以个promise是为了满足.then().then()链式调用 function newResolvedHandler(val) if (typeof resolvedHandler === ‘function‘) // 如果then第一个参数是函数 let result = resolvedHandler(val); if (result instanceof CPromise) // 如果函数返回是一个promise result.then(resolve, reject); else resolve(result); else resolve(val); function newRejectedHandler(val) if (typeof rejectedHandler === ‘function‘) // 如果then第一个参数是函数 let result = rejectedHandler(val); if (result instanceof CPromise) // 如果函数返回是一个promise result.then(resolve, reject); else reject(result); else reject(val); this.resolvedQueues.push(newResolvedHandler); // push到相应数组等到resolve时遍历执行里面函数 this.rejectedQueues.push(newRejectedHandler); // push到相应数组等到resolve时遍历执行里面函数 ); catch(rejectedHandler) return this.then(undefined, rejectedHandler); // 这里的catch实现其实是调用了then方法来实现 finally(finallyHandler) this.finayllyQueues.push(finallyHandler); static resolve(val) // 静态resolve方法 通过promise.resolve()方式调用 return new CPromise(resolve => resolve(val); ); static reject(val) // 静态reject方法 通过promise.reject()方式调用 return new CPromise((resolve, reject) => reject(val); ); static all(iterator) let len = iterator.length; let i = 0; let vals = []; return new CPromise( (resolve, reject) => iterator.forEach(it => it.then(val => i++; vals.push(val); if (i === len) // 当所有promise都被执行完了,才resolve结束 resolve(vals); ).catch(e=> reject(e); ); ); ); static race(iterator) // iterator 是一个promise数组 return new CPromise((resolve, reject) => iterator.forEach(it => it.then(val => // 返回封装成promise的数组,只要有一个被resolve就行 resolve(val); ).catch(e=> reject(e); ); ); )
有不对的地方,希望评论指正,个人看了些东西然后写下的一点点理解希望能对你有所帮助!!!
以上是关于js手写一个实现一个简单的promise__小前端chenMr的主要内容,如果未能解决你的问题,请参考以下文章