前言
最近很想研究一下Promise的原理,通过查阅资料写出了这篇博客,文章有借鉴参考文档。
正文
本文主要实现的是两个点,基本的Promise
和then
的链式调用。
代码的所有解释都在注释中
定义状态
//定义状态
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'
构造函数
function MyPromise(handle) {
//this.value 是resolve或rejecte状态的值
this.value = undefined
//初始化的Promise状态
this.status = PENDING
//分别是成功和失败回调函数的队列
this.fulfilledCallback = []
this.rejectedCallback = []
const resolve = value => {
//只有pending状态才能被改变,reject函数同理
if (this.status === PENDING) {
//改变状态
this.status = FULFILLED
//赋值给Promise的resolve状态下的值
this.value = value
//执行resolve的回调函数
this.fulfilledCallback.forEach(callback => callback(value))
}
}
const reject = value => {
if (this.status === PENDING) {
//改变状态
this.status = REJECTED
//赋值给Promise的reject状态下的值
this.value = value
//执行reject的回调函数
this.rejectedCallback.forEach(callback => callback(value))
}
}
try {
handle(resolve, reject)
} catch (err) {
reject(err)
}
}
then
MyPromise.prototype.then = function (onFulfilled = val=>val, onRejected = err=>{throw err}) {
//返回一个Promise
return new MyPromise((resolve, reject) => {
function handle(callback, value) {
try {
//判断then的参数是否是函数,不是则直接resolve这个新的Promise
if (typeof callback !== "function") {
return resolve(value)
}
const result = callback(value)
if (result instanceof MyPromise) {
//如果是Promsise类型,必须等待它的状态改变
result.then(resolve, reject)
} else {
//then的默认状态就是resolve
resolve(result)
}
} catch (err) {
reject(err)
}
}
//这里的this指向是调用then的那个Promise
if (this.status === FULFILLED) {
//同步任务进入
queueMicrotask(() => {
handle(onFulfilled, this.value)
})
} else if (this.status === REJECTED) {
//同步任务进入
queueMicrotask(() => {
handle(onRejected, this.value)
})
} else {
//异步任务 带着pending状态到这里=>注册回调函数=>等待resolve/reject来执行回调
//也就是说,如果Promise中的resolve不是异步的,根本注册不了回调函数,不会进入那两个数组
this.fulfilledCallback.push(value => {
queueMicrotask(() => {
handle(onFulfilled, value)
})
})
this.rejectedCallback.push(value => {
queueMicrotask(() => {
handle(onRejected, value)
})
})
}
})
}
实际测试
const fs = require('fs')
//为了测试MyPromise,封装了一个读文件函数
function readFile(path) {
return new MyPromise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) {
reject(err)
} else {
resolve(data.toString())
}
})
})
}
readFile('./a.txt')
.then(data => {
console.log(data)
return readFile('./b.txt')
})
.then('str')
.then(data => {
console.log(data)
})
//先输出a文件的内容,在输出b文件的内容,成功
参考文档
结语
如果对你有帮助的话,请点一个赞吧