ES6新增了一个用于处理异步操作数据的一个原生API,能够解决回调地狱的产生
常用的方法
- Promise.resolve()
- Promise.reject()
- Promise.then()
- Promise.catch()
- Promise.finally()
- Promise.all()
- Promise.race()
- Promise.allSettled()
- Promise.any()
接下来我们来使用代码来实现这些操作
实现Promise
首先我们在创建 Promise 实例,会传入两个函数用来表示成功的回调以及失败的回调,然后我们可以设计 Promise 类中的内容大概是这个样子的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| const PANDING = 'panding' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class Promise { constructor(fn) { this.state = PANDING this.resolveVal = null this.rejectVal = null fn(this.resolve.bind(this), this.reject.bind(this)) } resolve(value) { let s = setInterval(() => { if(this.state !== PANDING) { s && clearInterval(s) return } this.state = FULFILLED this.resolveVal = value || this.resolveVal },4) } reject(value) { let s = setInterval(() => { if(this.state !== PANDING) { s && clearInterval(s) return } this.state = REJECTED this.rejectVal = value || this.rejectVal }) } }
|
这样就实现了一个简单的Promise方法,并且更改状态之后就不可以在修改状态了,并且用两个变量来接收resolve
和reject
两个方法传入的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| Promise.prototype.then = function(resolve, reject) { let s = setInterval(() => { if(this.state !== PANDING) { s && clearInterval(s) try { let success = null let fail = null typeof resolve === 'function' && (success = getReturn(resolve.call(this, this.resolveVal))) typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal))) if(success) return Promise.resolve(success) if(fail) return Promise.resolve(fail) return this } catch (error) { return Promise.reject(error) } } },4) }
|
调用 then
方法时判断一下传入的是否是函数,如果是函数就直接调用,并把成功的参数传入
最后的 return this
则是为了实现链式结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Promise.prototype.catch = function(reject) { let s = setInterval(() => { if(this.state !== PANDING) { s && clearInterval(s) try { try { let fail = null typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal))) if(fail) return Promise.resolve(fail) return this } catch (error) { return Promise.reject(error) } } catch (error) { return Promise.reject(error) } } },4) }
|
1 2 3 4
| Promise.prototype.finally = function(fn) { fn() return this }
|
1 2 3 4
| Promise.resolve = function(value) { if(value instanceof Promise) return value return new Promise((resolve) => {resolve(value)}) }
|
这个稍微有些麻烦,我们需要判断传入的 value
是不是 Promise
类型的,如果是就可以直接返回,然后调用 .then
等方法,否则就需要我们创建一个 Promise 实例并返回
1 2 3 4
| Promise.reject = function(value) { if(value instanceof Promise) return value return new Promise((resolve, reject) => {reject(value)}) }
|
但是这里还有许多需要注意的地方,例如Promise.then
中如果有 return 的话则需要以返回的状态和值为主,如果没有,就以上一次的状态和值为主
同时还需要对代码使用 try...catch...
进行容错处理,使得在 catch 中能够拿到错误信息
代码修改如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Promise.prototype.then = function(resolve, reject) { try { let success = null let fail = null typeof resolve === 'function' && (success = getReturn(resolve.call(this, this.resolveVal))) typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal))) if(success) return Promise.resolve(success) if(fail) return Promise.resolve(fail) return this } catch (error) { return Promise.reject(error) } }
function getReturn(val) { if(typeof val === 'function') return val() return val }
|
实现Promise高级语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| Promise.all = function(arr) { try { if(arr instanceof Array) { return new Promise((resolve, reject) => { let resolveVal = [] let isReject = false for(let i = 0; i < arr.length; i++) { let res = getReturn(arr[i]) if(res instanceof Promise) { res.then(res1 => { resolveVal[i] = res1 }).catch(err => { reject(err) isReject = true }) } else resolveVal.push(res) if(isReject) break } resolve(resolveVal) }) } else throw new Error('Promise.all must receive Array') } catch (error) { if(error instanceof Error) throw error return Promise.reject(error) } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| Promise.race = function(arr) { try { if(arr instanceof Array) { return new Promise((resolve, reject) => { if(arr.length === 0) resolve() for(let i = 0; i < arr.length; i++) { let res = getReturn(arr[i]) if(res instanceof Promise) { res.then(res1 => { if(res1) { resolve(res) } }).catch(err => { if(err) { reject(err) } }) } else { resolve(res) break; } } }) } else throw new Error('Promise.all must receive Array') } catch (error) { if(error instanceof Error) throw error return Promise.reject(error) } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| Promise.allSettled = function(arr) { try { if(arr instanceof Array) { return new Promise((resolve, reject) => { let resolveVal = [] let length = 0 if(arr.length === 0) resolve([]) for(let i = 0; i < arr.length; i++) { let res = getReturn(arr[i]) if(res instanceof Promise) { res.then(res1 => { if(res1) { resolveVal[i] = { status: FULFILLED, value: res1 } if(++length === arr.length) resolve(resolveVal) } }).catch(err => { if(err) { resolveVal[i] = { status: REJECTED, value: err } if(++length === arr.length) resolve(resolveVal) } }) } else { resolveVal[i] = { status: FULFILLED, value: res } if(++length === arr.length) resolve(resolveVal) } } }) } else throw new Error('Promise.all must receive Array') } catch (error) { if(error instanceof Error) throw error return Promise.reject(error) } }
|
这些代码中还是有很多的bug
全部代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
| const PANDING = 'panding' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class Promise { constructor(fn) { this.state = PANDING this.resolveVal = null this.rejectVal = null fn(this.resolve.bind(this), this.reject.bind(this)) } resolve(value) { if(this.state !== PANDING) { return } this.state = FULFILLED this.resolveVal = value || this.resolveVal } reject(value) { if(this.state !== PANDING) { return } this.state = REJECTED this.rejectVal = value || this.rejectVal } } Promise.resolve = function(value) { if(value instanceof Promise) return value return new Promise((resolve) => {resolve(value)}) } Promise.reject = function(value) { if(value instanceof Promise) return value return new Promise((resolve, reject) => {reject(value)}) }
Promise.all = function(arr) { try { if(arr instanceof Array) { return new Promise((resolve, reject) => { let resolveVal = [] let isReject = false for(let i = 0; i < arr.length; i++) { let res = getReturn(arr[i]) if(res instanceof Promise) { res.then(res1 => { resolveVal[i] = res1 }).catch(err => { reject(err) isReject = true }) } else resolveVal.push(res) if(isReject) break } resolve(resolveVal) }) } else throw new Error('Promise.all must receive Array') } catch (error) { if(error instanceof Error) throw error return Promise.reject(error) } } Promise.race = function(arr) { try { if(arr instanceof Array) { return new Promise((resolve, reject) => { if(arr.length === 0) resolve() for(let i = 0; i < arr.length; i++) { let res = getReturn(arr[i]) if(res instanceof Promise) { res.then(res1 => { if(res1) { resolve(res) } }).catch(err => { if(err) { reject(err) } }) } else { resolve(res) } } }) } else throw new Error('Promise.all must receive Array') } catch (error) { if(error instanceof Error) throw error return Promise.reject(error) } } Promise.allSettled = function(arr) { try { if(arr instanceof Array) { return new Promise((resolve, reject) => { let resolveVal = [] let length = 0 if(arr.length === 0) resolve([]) for(let i = 0; i < arr.length; i++) { let res = getReturn(arr[i]) if(res instanceof Promise) { res.then(res1 => { if(res1) { resolveVal[i] = { status: FULFILLED, value: res1 } if(++length === arr.length) resolve(resolveVal) } }).catch(err => { if(err) { resolveVal[i] = { status: REJECTED, value: err } if(++length === arr.length) resolve(resolveVal) } }) } else { resolveVal[i] = { status: FULFILLED, value: res } if(++length === arr.length) resolve(resolveVal) } } }) } else throw new Error('Promise.all must receive Array') } catch (error) { if(error instanceof Error) throw error return Promise.reject(error) } } Promise.prototype.then = function(resolve, reject) { let s = setInterval(() => { if(this.state !== PANDING) { s && clearInterval(s) try { let success = null let fail = null typeof resolve === 'function' && (success = getReturn(resolve.call(this, this.resolveVal))) typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal))) if(success) return Promise.resolve(success) if(fail) return Promise.resolve(fail) return this } catch (error) { return Promise.reject(error) } } },4) } Promise.prototype.catch = function(reject) { let s = setInterval(() => { if(this.state !== PANDING) { s && clearInterval(s) try { try { let fail = null typeof reject === 'function' && (fail = getReturn(reject.call(this, this.rejectVal))) if(fail) return Promise.resolve(fail) return this } catch (error) { return Promise.reject(error) } } catch (error) { return Promise.reject(error) } } },4) } Promise.prototype.finally = function(fn) { fn() return this }
function getReturn(val) { if(typeof val === 'function') return val() return val }
|