前两天翻出以前写的各种手写原生代码,发现快忘干净了,最近准备重新捡起来
初步构建
简单实现一下”表面“上的Promise:
-
三个状态:pending,fulfilled,rejected
-
构造函数传入回调函数,回调函数传入两个函数,回调函数里可以调用类里的resolve,reject
-
resolve、reject的时候会改变内部状态,resolve传来的值会改变内部的value
class Promise {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
constructor(executer) {
this.status = Promise.PENDING
this.value = undefined
executer(this.resolve, this.reject)
}
resolve(result) {
this.value = result
this.status = Promise.FULFILLED
}
reject(reason) {
this.value = reason
this.status = Promise.REJECTED
}
}
const p = new Promise((resolve,reject)=>{
console.log(1)
resolve(1)
})
console.log(p)
/*ouput:
1
file:///D:/MYSOURSE/project/nodejs/promise.js:10
resolve() {this.status = Promise.FULFILLED}
^
TypeError: Cannot set property 'status' of undefined
at resolve (file:///D:/MYSOURSE/project/nodejs/promise.js:10:28)
at file:///D:/MYSOURSE/project/nodejs/promise.js:16:5
at new Promise (file:///D:/MYSOURSE/project/nodejs/promise.js:8:9)
at file:///D:/MYSOURSE/project/nodejs/promise.js:14:11
at ModuleJob.run (internal/modules/esm/module_job.js:146:23)
at async Loader.import (internal/modules/esm/loader.js:165:24)
at async Object.loadESM (internal/process/esm_loader.js:68:5)
*/
报错了,写的很明白,status是个undefined,也就是this对象上没有这个东西,所以this是谁呢,简单分析一下:constructor接收一个回调函数,回调函数里传入类里的resolve,当回调函数执行的时候会调用参数里的resolve方法,这个是在executer里调用的,谁调用的this就指向谁,executer的this是window,resolve也是window调用的,但是在类里默认开启了严格模式,所以this指向undefined
解决方法:bind绑定this
class Promise {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
constructor(executer) {
this.status = Promise.PENDING
executer(this.resolve.bind(this), this.reject.bind(this))
}
resolve(result) {
this.value = result
this.status = Promise.FULFILLED
}
reject(reason) {
this.value = reason
this.status = Promise.REJECTED
}
}
const p = new Promise((resolve,reject)=>{
console.log(1)
resolve(1)
})
console.log(p)
/*
output:
1
Promise { status: 'fulfilled' }
*/
继续照着原始的Promise开始模仿
完善resolve、reject方法:
根据PromiseA+规范:
一个Promise必须处在其中之一的状态:pending, fulfilled 或 rejected.
- 如果是pending状态,则promise:
- 可以转换到fulfilled或rejected状态。
- 如果是fulfilled状态,则promise:
- 不能转换成任何其它状态。
- 必须有一个值,且这个值不能被改变。
- 如果是rejected状态,则promise可以:
- 不能转换成任何其它状态。
- 必须有一个原因,且这个值不能被改变。
所以在改变状态的时候加个判断,只有状态是pending的时候才能改变:
resolve(result) {
if (this.status === Promise.PENDING) {
this.value = result
this.status = Promise.FULFILLED
}
}
reject(reason) {
if (this.status === Promise.PENDING) {
this.value = reason
this.status = Promise.REJECTED
}
}
then方法
then方法接受两个函数,一个是resolve时调用的,一个是reject时调用的,只要then方法传来了参数,把他暂存一下,当状态改变的时候再调用对应的方法就好了
constructor里声明一个成功和失败的回调函数:
constructor(executer) {
this.status = Promise.PENDING
this.value = undefined
this.successCallback = () => {
}
this.failCallback = () => {
}
executer(this.resolve.bind(this), this.reject.bind(this))
}
then方法:
then(onFulfilled, onRejected) {
// 没有传函数的时候默认给个什么都不干的函数
if (typeof onFulfilled !== 'function') {
onFulfilled = () => {
}
}
if (typeof onRejected !== 'function') {
onRejected = () => {
}
}
// 当前状态是pending的时候,说明有任务还没有resolve,这时候暂存一下
if (this.status === Promise.PENDING) {
this.successCallback = () => {
onFulfilled(this.value)
}
this.failCallback = () => {
onRejected(this.value)
}
}
// 执行到then的时候前面的状态已经改变了,说明走的是同步代码,直接执行就好了
if (this.status === Promise.FULFILLED) {
onFulfilled(this.value)
}
if (this.status === Promise.REJECTED) {
onRejected(this.value)
}
}
resolve方法:
resolve(result) {
if (this.status === Promise.PENDING) {
this.value = result
this.status = Promise.FULFILLED
// 执行到这里的时候任务已经resolve了,调用callback
this.successCallback()
}
}
测试:
const p = new Promise((resolve, reject) => {
console.log(1)
resolve(22)
}).then(res => {
console.log(res)
})
console.log(p)
/*
output:
1
22
undefined
*/
现在其实有点问题:
- 首先打印的顺序问题,Promise的异步任务应该晚于打印p执行;
- 打印的p是undefined说明then没有返回值,没有实现链式调用;
- 回调函数每个状态就那么一个函数,如果多个任务肯定是不够用,虽然现在then还不能链式调用,且听下回分解