Promise
是 ES6 推出的用于解决callback
嵌套层级太深问题的一种异步方案.
基本使用如下.
let myPromise = new Promise((resolve,reject) => {
setTimeout(()=>{
resolve("true") // reject("false")
},1000)
})
myPromise.then(data=>{
console.log(data)
},err=>{
console.log(err)
})
先不考虑那么多,也不像很多博客里写的那种,一上来就给非常完美的思路和非常标准的 Promise/A+
规范.
我就按照自己思路一点点的来做.
step 01 从代码代用级别摸清内部构造
- 一个 Promise 对象,有三个状态.
- 初始状态是 pending.
- 成功状态是 resolve.
- 失败状态是 reject.
然后看上述写的代码.
let myPromise = new Promise((resolve,reject) => {
setTimeout(()=>{
resolve("true") // reject("false")
},1000)
})
- new Promise () 是一个构造函数,没什么好说的.
function MyPromise () {
}
// 肯定是
let my_promise = new MyPromise()
- 这个构造函数接受的参数也是一个函数,也没什么好说的.
function MyPromise (func) {
typeof func === 'function' ===> true
}
- 在这个函数参数里我们声明了 resolve 和 reject 两个形参.
function MyPromise((resolve,reject) => {
typeof reject === 'function' // true
typeof resolve === 'function' // true
})
- 在后续的使用参数的过程中,我们可以知道,是构造函数传入的执行器,在内部调用了这两个reject 和 resolve
function MyPromise() {
//xxx
}
new MyPromise((resolve,reject) => {
setTimeout(() => {
reslove(data) // or reject (err)
},1000)
})
- reject 和 resolve 肯定不是由传递进去的参数自己提供的.
function MyPromise() {
//xxx
}
new MyPromise((resolve,reject) => {
setTimeout(() => {
// resovle 哪来的?
reslove(data) // or reject (err) // reject 哪来的?
},1000)
})
- 那么就只有一个可能,那是 Promise 内部提供的两个功能函数.
function MyPromise () {
function resolve () {}
function reject () {}
}
- 其中 resolve 函数别的不管,起码应该会把当前 promise 对象的状态由 pending --> resolve reject 同理, 从 pending --> reject
function MyPromise () {
function resolve () {
// pending ---> resolve
}
function reject () {
// pending ---> reject
}
}
- 调用 then 实例方法,会将两种状态的回调函数传递进去.
new MyPromise(executor).then(resolveData=>{},rejectData=>{})
step 02 根据上述推理,猜测内部写法.
1. 首先是一个构造函数
function MyPromise () {
}
2. 其次需要接受一个执行器.
function MyPromise (executor) {
}
3. 实例化出来的 Promise 对象有三种状态
MyPromise.prototype.states = {
PENDING: 'PENDING',
RESOLVE: 'RESOLVE',
REJECT: 'REJECT'
}
4. 一开始 promise 对象是 pending 状态
function MyPromise (executor) {
this.state = this.states.PENDING // pending.
}
5. 内部起码得有两个 reject 和 resolve.要不然executor里面的reject 和 resolve 哪来的? 或者把这两个方法
function MyPromise (executor) {
this.state = this.states.PENDING // pending.
const that = this // 挂载 this
function resolve () {
if (that.state === this.states.PENDING) {
that.state = this.states.PENDING
}
}
function reject () {
if (that.state === this.states.PENDING) {
that.state = this.states.REJECT
}
}
}
或者觉得挂载 this 麻烦,我就把 resolve 和 reject 挂在 prototype 上.
MyPromise.prototype.reject = function () {
if (this.state === this.states.PENDING) {
this.state = this.states.REJECT
}
}
MyPromise.prototype.resolve = function () {
if (this.state === this.states.PENDING) {
this.state = this.states.RESOLVE
}
}
到目前为止,我们可以通过 executor 内部调用 reject 或者 resolve 修改某个 Promise 的状态了.
在回到我们使用 ES6 的 Promise 代码中.
new Promise ((resolve,reject) => {
resolve(someData) // or reject(someError)
})
可以知道 reslove 和 reject 是可以接受参数的.
- 对于 resolve 来说,参数就是 executor 执行成功返回的的值.
- 对于 reject 来说,参数就是 executor 执行失败返回的值.
6. 给 reject 和 resolve 来设置一个形参
// reject 给 error 形参
MyPromise.prototype.reject = function (error) {
if (this.state === this.states.PENDING) {
this.state = this.states.REJECT
}
}
// resolve 给 data 形参
MyPromise.prototype.resolve = function (data) {
if (this.state === this.states.PENDING) {
this.state = this.states.RESOLVE
}
}
7.我们通过 then 传递了两个函数,第一个是成功的回调. 第二个是失败的回调.
MyPromise.prototype.then = function (onResolve,onReject) {
this.onResloveCallback = onResolve
this.onRejectCallback = onReject
}
在回到 ES6 的 Promise 调用代码中.
let p = new Promise((resolve,reject) => {
setTimeout(()=>{
resolve(data形参) // reject(失败形参)
},1000)
})
p.then(data=>{
data === data 形参
})
8.resolve的形参传递给了then的第一个回调函数的参数,error传递给了then的第二个回调函数的参数
// reject 给 error 形参
MyPromise.prototype.reject = function (error) {
if (this.state === this.states.PENDING) {
this.state = this.states.REJECT
this.error = error
}
}
// resolve 给 data 形参
MyPromise.prototype.resolve = function (data) {
if (this.state === this.states.PENDING) {
this.state = this.states.RESOLVE
this.data = data
}
}
9. 状态改变完成之后,就需要调用从then函数接受过来的两个函数参数了(reject&resolve)
// reject 给 error 形参
MyPromise.prototype.reject = function (error) {
if (this.state === this.states.PENDING) {
this.state = this.states.REJECT // 该状态
this.error = error // 记录值
this.onRejectCallback(this.error) // 调用回调
}
}
// resolve 给 data 形参
MyPromise.prototype.resolve = function (data) {
if (this.state === this.states.PENDING) {
this.state = this.states.RESOLVE // 改状态
this.data = data // 记录值
this.onResolveCallback(data) // 调用回调
}
}
完整的代码
function MyPromise (executor) {
this.state = this.states.PENDING
this.value = null // 用于记录executor内部的reject or resolve 传递回来的值.
this.onRejectCallback = null
this.onResolveCallback = null
executor(this.resolve.bind(this),this.reject.bind(this))
}
MyPromise.prototype.states = {
PENDING: 'PENDING',
RESOLVE: 'RESOLVE',
REJECT: 'REJECT'
}
// reject 给 error 形参
MyPromise.prototype.reject = function (error) {
if (this.state === this.states.PENDING) {
this.state = this.states.REJECT // 该状态
this.error = error // 记录值
this.onRejectCallback(this.error) // 调用回调
}
}
// resolve 给 data 形参
MyPromise.prototype.resolve = function (data) {
if (this.state === this.states.PENDING) {
this.state = this.states.RESOLVE // 改状态
this.data = data // 记录值
this.onResolveCallback(data) // 调用回调
}
}
step 03 . 测试MyPromise 的 resolve 和 reject
测试调用自定义的promise ---> pending --> resolve
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000);
}).then(data => { console.log(data) }, error => { console.log(error) })
正确输出.
测试调用自定义的promise ---> pending --> reject
new MyPromise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, 1000);
}).then(data => { console.log(data) }, error => { console.log(error) })
错误输出.
第一阶段手写 Promise 达成目标:
- 状态改变 [✅]
- 正确的调用then的函数接受的两个回调函数.[✅]
补充一点:
如果把 reject 和 resolve 写在 prototype 上,然后直接通过 this.reject/resolve 传递会导致 this 指向的错误(obj.method当函数传递,只能传 method, 不会传 obj,真正的纯函数传递).所以,上述代码一定要写成.
executor(this.resolve.bind(this),this.reject.bind(this))