当我们使用axios时发生了什么?
1 2 3
| axios.get() .then((data)=>{conolse.log(data)}) .catch((error)=>{console.log(error)})
|
axios会生成一个promise对象,对象状态为pending。
如果后端返回成功,则promise调用promise内置的resolve方法将状态改为fullfilled,并且value被传递给then中的方法,then方法中的回调函数被添加到微任务队列。假设我们只执行这一行,则微任务队列为空,立即执行then中的方法。
如果后端返回失败,则promise调用promise内置的reject方法将状态改为rejected,并且 reason(拒绝的原因)会被传递给紧随其后的 .catch() 方法的回调函数,catch方法中的回调函数被添加到微任务队列,假设我们只执行这一行,则微任务队列为空,立即执行catch中的方法。
手写promise.all
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
| Promise.all2 = (promises) => { return new Promise((resolve, reject) => { if (promises.length === 0) { resolve() return } if (promises.length !== 0) { let counter = 0 let results = new Array(promises.length) for (let i = 0; i < promises.length; i++) { Promise.resolve(promises[i]) .then((value) => { counter += 1 results[i] = value if (counter == promises.length) { resolve(results) } }) .catch(() => { reject('出错了') }) } }
}) }
const promise1 = Promise.resolve(3); const promise2 = 42; const promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('foo') }, 100); });
Promise.all2([promise1, promise2, promise3]).then(values => { console.log(values); }).catch(error => { console.error(error); });
|
手写promise
在实现之前,时刻铭记:If we do not want execute immediately, we need to put it into a function and call it when desired.
并且我们需要知道正常的promise具备了哪些功能,一般来说,常用的promise使用为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve(res); }, 1000); });
promise.then((res) => { console.log(res); }, (err) => { console.log(err); }); promise.catch((err) => { console.log(err); }); promise.finally(() => { console.log("finally over"); });
|
所以我们要实现:
- 对Promise传入callback
- 当resolved时,执行then中的callback
- 当rejected时,执行catch中的callback
- 不管resolved还是rejected,都执行finally中的callback
首先先实现then
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
| const FULFILLED = 'fulfilled' const PENDING = 'pending' const REJECTED = 'rejected'
function MyPromise(handler) { this.status = PENDING this.value = undefined this.onFulFilledCallbacks = [] this.onRejectedCallbacks = []
const resolve = (val) => { if (this.status === PENDING) { this.status = FULFILLED this.value = val this.onFulFilledCallbacks.forEach(f => f(val)) } }
const reject = (err) => { if (this.status === PENDING) { this.status = REJECTED this.value = err this.onRejectedCallbacks.forEach(f => f(err)) } }
try { handler(resolve, reject) } catch (error) { reject(error) } }
MyPromise.prototype.then = function (onFulfilled, onRejected) { if (this.status === FULFILLED) { onFulfilled(this.value) } else if (this.status === REJECTED) { onRejected(this.value) } else { this.onFulFilledCallbacks.push(onFulfilled) this.onRejectedCallbacks.push(onRejected) } }
const p1 = new MyPromise((resolve, reject) => { setTimeout((v) => { resolve(v) }, 1000, 'ok') })
const p2 = new MyPromise((resolve, reject) => { setTimeout((v) => { resolve(v) }, 1000, 'fail') })
p1.then(v => { console.log(v) }, err => { console.log(err) })
p2.then(v => { console.log(v) }, err => { console.log(err) })
|
当我们在执行p1.then()时,p1仍处于pending状态,所以两个回调分别加入成功队列和失败队列。
等待1s后,p1状态变为fulfilled,并开始执行成功队列的方法。
我们实现了then,但是这个then是没有返回值的,所以也不支持链式调用。链式调用可以让代码更清晰,所以很有必要支持,支持链式调用就需要返回一个新的promise,实现如下: