首先咱们先看一下promise是如何使用的:javascript
<script> let p1=new Promise((resolve,reject)=>{ resolve() }) p1.then(()=>{ console.log(123) }) </script>
经过promise构建出来的对象有三种状态,Pending(进行中),Fulfilled(已成功),Rejected(已失败)java
状态只能由 Pending 变为 Fulfilled 或由 Pending 变为 Rejected ,且状态改变以后不会在发生变化,会一直保持这个状态。
经过then函数注册成功或者失败函数,promise内部调用resolve或者reject调用对应的函数。jquery
; (function () { const status = { 0: "pending", 1: "fulfilled", 2: "rejected" } class customePromise { constructor(func) { if (typeof func != "function") { throw TypeError("Promise resolver " + func + " is not a function") } func(this._resolve.bind(this), this._reject.bind(this)); } _resolve(val) { } _reject(val) { } } window.customePromise = customePromise; })();
首先咱们定义了一个customePromise的类,经过window暴露出去,经过前面promise调用咱们能够看到参数是一个函数,该函数接受两个参数,resolve,reject,经过调用两个函数来执行对应的成功或者失败函数。第一步,咱们在内部首先要判断传入是否为一个函数,才进行下一步操做。数组
; (function () { const status = { 0: "pending", 1: "fulfilled", 2: "rejected" } class customePromise { constructor(func) { this._status = status[0]; this.resolveArr = []; this.rejectArr = []; this.value=""; if(typeof func!="function"){ throw TypeError("Promise resolver "+ func+" is not a function") } try { func(this._resolve.bind(this), this._reject.bind(this)); } catch (err) { this._reject(err) } } _resolve(val) { } _reject(val) { } } window.customePromise = customePromise; })();
promise最大的好处就是他的捕获机制,一旦你在外部函数吃错均可以在内部能够捕获到,这样你外面的脚本还能继续往下执行,并经过失败函数能够打印出来。promise
一开始咱们在构造函数开始执行的时候保存了这个对象状态为pending,而后在这个promise对象上挂载了两个属性用来保存成功和失败函数。下面咱们来实现then函数异步
then(resolveFunc, rejectFunc) { switch (this._status) { case "pending": this.resolveArr.push(resolveFunc); this.rejectArr.push(rejectFunc); break; case "fulfilled": resolvefunc(this.value) break; case "rejected": rejectfunc(this.value) break; } }
经过判断promise对象来决定函数是否执行,若是处于pending状态,就把成功失败函数存入对应的数组,若是状态已经改变,就执行对应的函数。下面实现成功失败函数的代码。函数
_resolve(val) { setTimeout(() => { this.value=val; this._status = status[1]; this.resolveArr.forEach(item => { item(val); }) }, 0) } _reject(val) { setTimeout(() => { this.value=val; this._status = status[2]; this.rejectArr.forEach(item => { item(val); }) }, 0) }
注意下咱们的promise属于微任务,他会让咱们主线程的任务先执行,因此咱们这里采用异步模拟。但这里仍是存在一个问题,就是咱们能够在外部屡次调用,这明显是不容许,因此咱们来优化下代码。优化
_resolve(val) { setTimeout(() => { if (this._status != status[0]) { return; } this.value=val; this._status = status[1]; this.resolveArr.forEach(item => { item(val); }) }, 0) } _reject(val) { setTimeout(() => { if (this._status != status[0]) { return; } this.value=val; this._status = status[2]; this.rejectArr.forEach(item => { item(val); }) }, 0) }
用过jquery的同窗都知道jquery是能够链式调用,一样咱们的promise也是能够的,那就表示咱们的then函数返回值一样也是个promise对象,下面咱们来改写then函数。this
then(resolveFunc, rejectFunc) { let resolvefunc, rejectfunc; let _this = this; return new customePromise(function (resolve, reject) { resolvefunc = function (val) { let value = resolveFunc(val); resolve(value) } rejectfunc = function (val) { let value = rejectFunc(val); reject(value) } switch (_this._status) { case "pending": _this.resolveArr.push(resolvefunc); _this.rejectArr.push(rejectfunc); break; case "fulfilled": resolvefunc() break; case "rejected": rejectfunc break; } }) }
注意这里并很差理解,由于以前咱们存入的事成功和失败函数,这里咱们包装了一个函数并把then函数返回值promise对象的resolve函数也存入进去,这就表示若是咱们第一个promise状态改变会接着触发第二个promise对象的执行,但须要注意若是咱们函数的返回值一样是一个promise对象的话,咱们必要要等待其状态改变才能触发他的下一个的then函数,这是一个难点,很很差理解,咱们使用过把then函数返回的promise对象的resolve时间挂在函数内部的then上面,一旦内部函数状态改变会触发then函数的对应的事件,固然咱们也是要加上容错处理,下面附上代码: 线程
then(resolveFunc, rejectFunc) { let resolvefunc, rejectfunc; let _this = this; return new customePromise(function (resolve, reject) { resolvefunc = function (val) { try { if (typeof resolveFunc != "function") { resolve(val) } else { let value = resolveFunc(val); if (value instanceof customePromise) { value.then(resolve) } else { resolve(value) } } } catch (err) { console.log(err) reject(err) } } rejectfunc = function (val) { try { if (typeof rejectFunc != "function") { resolve(val) } else { let value = rejectFunc(val); if (value instanceof customePromise) { value.then(reject) } else { reject(value) } } } catch (err) { reject(err) } } switch (_this._status) { case "pending": _this.resolveArr.push(resolvefunc); _this.rejectArr.push(rejectfunc); break; case "fulfilled": resolvefunc() break; case "rejected": rejectfunc break; } }) }
最后说一下resolve()参数若是是一个promise对象的话,必需要等待参数的状态改变才能触发他的then函数,原理跟上面的很类似。
_resolve(val) { setTimeout(() => { if (val instanceof customePromise) { val.then(()=>{ this._status = status[1]; this.resolveArr.forEach(item => { item(val); }) }) return; } if (this._status != status[0]) { return; } this._status = status[1]; this.resolveArr.forEach(item => { item(val); }) }, 0) } _reject(val) { setTimeout(() => { if (val instanceof customePromise) { val.then(()=>{ this._status = status[2]; this.rejectArr.forEach(item => { item(val); }) }) return; } if (this._status != status[0]) { return; } this._status = status[2]; this.rejectArr.forEach(item => { item(val); }) }, 0) }
最后附上全部的代码:
; (function () { const status = { 0: "pending", 1: "fulfilled", 2: "rejected" } class customePromise { constructor(func) { this._status = status[0]; this.resolveArr = []; this.rejectArr = []; if(typeof func!="function"){ throw TypeError("Promise resolver "+ func+" is not a function") } try { func(this._resolve.bind(this), this._reject.bind(this)); } catch (err) { this._reject(err) } } _resolve(val) { setTimeout(() => { if (val instanceof customePromise) { val.then(()=>{ this._status = status[1]; this.resolveArr.forEach(item => { item(val); }) }) return; } if (this._status != status[0]) { return; } this._status = status[1]; this.resolveArr.forEach(item => { item(val); }) }, 0) } _reject(val) { setTimeout(() => { if (val instanceof customePromise) { val.then(()=>{ this._status = status[2]; this.rejectArr.forEach(item => { item(val); }) }) return; } if (this._status != status[0]) { return; } this._status = status[2]; this.rejectArr.forEach(item => { item(val); }) }, 0) } then(resolveFunc, rejectFunc) { let resolvefunc, rejectfunc; let _this = this; return new customePromise(function (resolve, reject) { resolvefunc = function (val) { try { if (typeof resolveFunc != "function") { resolve(val) } else { let value = resolveFunc(val); if (value instanceof customePromise) { value.then(resolve) } else { resolve(value) } } } catch (err) { console.log(err) reject(err) } } rejectfunc = function (val) { try { if (typeof rejectFunc != "function") { resolve(val) } else { let value = rejectFunc(val); if (value instanceof customePromise) { value.then(reject) } else { reject(value) } } } catch (err) { reject(err) } } switch (_this._status) { case "pending": _this.resolveArr.push(resolvefunc); _this.rejectArr.push(rejectfunc); break; case "fulfilled": resolvefunc() break; case "rejected": rejectfunc break; } }) } } window.customePromise = customePromise; })();