本文共 3397 字,大约阅读时间需要 11 分钟。
最近很想研究一下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) }}
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文件的内容,成功
如果对你有帮助的话,请点一个赞吧
转载地址:http://wrozi.baihongyu.com/