Promise从0到自定义
1. Promise是什么?
Promise是一个构造函数,用于表示一个异步操作的最终完成 (或失败), 及其结果值.
2. Promise用来解决我们开发中什么问题?
Promise用来解决我们日常开发中产生的回调嵌套(回调地狱)问题.
3. Promise实例对象内部的三种状态
* pending:初始状态,既不是成功,也不是失败状态
* resolved/fulfilled: 成功状态
* rejected:失败状态
4. Promise语法研究
1. Promise构造函数会把一个叫做“处理器函数”(executor function)的函数作为它的参数
2. Promise构造函数执行时立即调用executor函数
3. executor函数接受两个函数(resolve和reject)作为其参数
4. resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)
5. resolve/reject函数分别都接受一个参数,供之后调用then/catch函数传递的参数,默认是undefined
6. 当异步任务顺利完成且返回结果值时,会调用 resolve 函数
7. 当异步任务失败且返回失败原因时,会调用reject 函数
8. 一个promise内部状态只能被修改一次
9. executor函数中抛出一个错误,那么该promise 状态为rejected
function MyPromise (executor) {
this._status = 'pending'
this._value = undefined
const resolve = value => {
if (this._status !== 'pending') return
this._status = 'resolved'
this._value = value
}
const reject = reason => {
if (this._status !== 'pending') return
this._status = 'rejected'
this._value = reason
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
const promise = new MyPromise((resolve, reject) => {
resolve(1111)
reject(222)
})
console.log(promise)
5. Promise原型上的方法
1. then(onResolved,onRejected) ==> 添加成功(onResolved)和失败(onRejected)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve
2. catch(onRejected) ==> 添加一个失败(rejection) 回调到当前 promise, 返回一个新的promise。当这个 回调函数被调用,新 promise 将以它的返回值来resolve,否则如果当前promise 进入fulfilled状态,则以当 前promise的完成结果作为新promise的完成结果.
3. finally() ==> 添加一个事件处理回调于当前promise对象,并且在原promise对象解析完毕后,返回一个新的 promise对象。回调会在当前promise运行完毕后被调用,无论当前promise的状态是完成(fulfilled)还是失败 (rejected)
6. then语法研究
1. then() 方法返回一个 Promise。它最多需要有两个参数:Promise 的成功和失败情况的回调函数
2. then方法内部接受2个回调函数,onResolved/onRejected 对应 `成功和失败的回调`
3. 当上一个promise状态变成`resolved(成功)`,调用`onResolved回调`
4. 当上一个promise状态变成`rejected(失败)`,调用`onRejected回调`
5. onResolved/onRejected回调中都接受一个参数,参数内容为上一个promise内部传递的值
7. then方法返回的Promise状态研究
1. 回调函数内部返回了一个值,那么就返回一个成功状态的promise,并且将返回的值作为接受状态的回调函数的参数值
2. 没有返回任何值,那么 then 返回的 Promise 将会成为成功状态,该接受状态的回调函数的参数值为 undefined
3. 抛出一个错误,那么 then 返回的 Promise 将会成为失败状态,并且将抛出的错误作为失败状态回调函数的参数值
4. 返回一个已经是成功状态的 Promise,那么 then 返回的 Promise 也会成为成功状态,并且将那个 Promise 的成功状态的回调函数的参数值作为该被返回的Promise的成功状态回调函数的参数值。
5. 返回一个已经是失败状态的 Promise,那么 then 返回的 Promise 也会成为失败状态,并且将那个 Promise 的失败状态的回调函数的参数值作为该被返回的Promise的失败状态回调函数的参数值。
6. 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是 相同的。
先简单实现 不同状态调用不同回调:
MyPromise.prototype.then = function (onResolved, onRejected) {
if (this._status === 'resolved') {
onResolved(this._value)
} else if (this._status === 'rejected') {
onRejected(this._value)
} else {
}
}
8. then方法的链式调用
链式调用:返回值还是一个promise,至于是什么状态的promise看上面我们说的
## 怎么确定一个函数的返回值还是一个promise呢?
return new Promise((resolve,reject) =>{}) 作为其返回值
## 返回的promise是什么状态的?
看上面总结的
## 我们来实现
MyPromise.prototype.then = function (onResolved, onRejected) {
return new Promise((resolve, reject) => {
if (this._status === 'resolved') {
const res = onResolved(this._value)
try {
res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
} else if (this._status === 'rejected') {
const res = onRejected(this._value)
try {
res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
} else {
}
})
}
## 测试:
const promise = new MyPromise((resolve, reject) => {
reject(1)
})
promise.then(value => {
console.log(value)
}, reason => {
console.log(reason)
})
.then(value => {
console.log(2)
})
.then(value => {
console.log(3)
})
.then(value => {
console.log(4)
})
测试结果:1 2 3 4
9. pending状态内部如何处理?
`上面我们实现了promise的链式调用,那么我们来思考一个问题: 如果内部是异步执行,那么结果会是怎样的呢?`
代码如下:
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1111)
}, 1000)
})
promise.then(value => {
console.log(value)
}, reason => {
console.log(reason)
})
.then(value => {
console.log(2222)
})
.then(value => {
console.log(3333)
})
.then(value => {
console.log(4444)
})
测试结果: `没有任何输出`
那咱们来捋一下代码逻辑:
`当我们去new Promise的时候,我们会去调用executor执行器函数,然后定时器1s后执行,但是我们代码并不会等待定时器到点了在去执行下面代码,也就是说定时器在等待中的时候我们的then方法就已经调用了,但是此时我们的promise内部状态还是pending状态,所以并不会触发任何一个回调,然后代码执行完之后,定时器到点,调用resolve函数,resolve函数内部仅仅改变了状态和value值,并没有去调用then方法内部的任何一个回调,所以结果没有任何输出,也就是说,在promise处于pending状态的时候,我们并没有做任何事情`
# 思考: pending状态的时候应该做什么事情?
`我们可以在pending状态的时候用一个容器存储着成功和失败的回调,然后在resolve/reject函数内部去调用这个容器中存储的成功或者失败回调`
那么咱们来实现一下:
MyPromise.prototype.then = function (onResolved, onRejected) {
return new Promise((resolve, reject) => {
if (this._status === 'resolved') {
const res = onResolved(this._value)
try {
res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
} else if (this._status === 'rejected') {
const res = onRejected(this._value)
try {
res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
} else {
this._callbacks.push({
onResolved: () => {
const res = onResolved(this._value)
try {
res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
},
onRejected: () => {
const res = onRejected(this._value)
try {
res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
}
})
}
})
}
Promise构造函数中代码如下:
function MyPromise (executor) {
this._status = 'pending'
this._value = undefined
this._callbacks = []
const resolve = value => {
if (this._status !== 'pending') return
this._status = 'resolved'
this._value = value
this._callbacks.length && this._callbacks.forEach(cb => cb.onResolved(value))
}
const reject = reason => {
if (this._status !== 'pending') return
this._status = 'rejected'
this._value = reason
this._callbacks.length && this._callbacks.forEach(cb => cb.onRejected(reason))
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
return new Promise((resolve, reject) => {
switch (this._status) {
case 'resolved':
PromiseThenPublicCode(onResolved, this._value, resolve, reject)
break;
case 'rejected':
PromiseThenPublicCode(onRejected, this._value, resolve, reject)
break;
default:
this._callbacks.push({
onResolved: () => {
PromiseThenPublicCode(onResolved, this._value, resolve, reject)
},
onRejected: () => {
PromiseThenPublicCode(onRejected, this._value, resolve, reject)
}
})
break;
}
})
}
function PromiseThenPublicCode (onFn, value, resolve, reject) {
const res = onFn(value)
try {
res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
}
MyPromise.prototype.then = function (onResolved, onRejected) {
return new Promise((resolve, reject) => {
switch (this._status) {
case 'resolved':
PromiseThenPublicCode(onResolved, this._value, resolve, reject)
break;
case 'rejected':
PromiseThenPublicCode(onRejected, this._value, resolve, reject)
break;
default:
this._callbacks.push({
onResolved: () => {
PromiseThenPublicCode(onResolved, this._value, resolve, reject)
},
onRejected: () => {
PromiseThenPublicCode(onRejected, this._value, resolve, reject)
}
})
break;
}
})
}
console.log(0)
const promise = new MyPromise((resolve, reject) => {
resolve(1)
})
promise
.then(value => {
console.log(value)
})
.then(value => {
console.log(2)
})
.then(value => {
console.log(3)
})
.then(value => {
console.log(4)
})
console.log(5)
function PromiseThenPublicCode (onFn, value, resolve, reject) {
setTimeout(() => {
const res = onFn(value)
try {
res instanceof MyPromise ? res.then(resolve, reject) : resolve(res)
} catch (error) {
reject(error)
}
})
}