有你在真好 的个人博客
手写简单的Promise实现
阅读:2190 添加日期:2021/3/27 23:16:04 原文链接:https://www.toutiao.com/item/6727459848868332044/

一、基础版本

目标

  1. 可以创建promise对象实例。
  2. promise实例传入的异步方法执行成功就执行注册的成功回调函数,失败就执行注册的失败回调函数。
手写简单的Promise实现

实现

废话不多说,直接上代码:

function MyPromise(fn) {
 let self = this; // 缓存当前promise实例
 self.value = null; //成功时的值
 self.error = null; //失败时的原因
 self.onFulfilled = null; //成功的回调函数
 self.onRejected = null; //失败的回调函数
 function resolve(value) {
 self.value = value;
 self.onFulfilled(self.value);//resolve时执行成功回调
 }
 function reject(error) {
 self.error = error;
 self.onRejected(self.error)//reject时执行失败回调
 }
 fn(resolve, reject);
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
 //在这里给promise实例注册成功和失败回调
 this.onFulfilled = onFulfilled;
 this.onRejected = onRejected;
}
module.exports = MyPromise

代码很短,逻辑也非常清晰,在then中注册了这个promise实例的成功回调和失败回调,当promise reslove时,就把异步执行结果赋值给promise实例的value,并把这个值传入成功回调中执行,失败就把异步执行失败原因赋值给promise实例的error,并把这个值传入失败回调并执行。

测试代码:

 let Promise = require("./mypromise")
	let fs = require("fs")
	
	let promise = new Promise((resolve, reject) => {
	 fs.readFile('../file/1.txt', "utf8", function(err, data) {
	 err ? reject(err) : resolve(data)
	 });
	});
	function successLog(data) {
	 console.log(data)
	}
	function errorLog(error) {
	 console.log(error)
	}
	promise.then(successLog, errorLog);

二. 支持同步任务

我们知道,我们在使用es6 的promise时,可以传入一个异步任务,也可以传入一个同步任务,但是我们的上面基础版代码并不支持同步任务,如果我们这样写就会报错:

let promise = new Promise((resolve, reject) => {
 resolve("同步任务执行")
});

为什么呢?因为是同步任务,所以当我们的promise实例reslove时,它的then方法还没执行到,所以回调函数还没注册上,这时reslove中调用成功回调肯定会报错的。

目标

使promise支持同步方法

实现

function resolve(value) {
 //利用setTimeout特性将具体执行放到then之后
 setTimeout(() => {
 self.value = value;
 self.onFulfilled(self.value)
 })
}
function reject(error) {
 setTimeout(() => {
 self.error = error;
 self.onRejected(self.error)
 })
}

实现很简单,就是在reslove和reject里面用setTimeout进行包裹,使其到then方法执行之后再去执行,这样我们就让promise支持传入同步方法,另外,关于这一点,Promise/A+规范里也明确要求了这一点。

2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code.

三. 支持三种状态

我们知道在使用promise时,promise有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。另外,promise一旦状态改变,就不会再变,任何时候都可以得到这个结果promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,如果改变已经发生了,你再对promise对象添加回调函数,也会立即得到这个结果。

目标

  1. 实现promise的三种状态。
  2. 实现promise对象的状态改变,改变只有两种可能:从pending变为fulfilled和从pending变为rejected。
  3. 实现一旦promise状态改变,再对promise对象添加回调函数,也会立即得到这个结果。

实现

//定义三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function MyPromise(fn) {
 let self = this;
 self.value = null;
 self.error = null;
 self.status = PENDING;
 self.onFulfilled = null;
 self.onRejected = null;
 function resolve(value) {
 //如果状态是pending才去修改状态为fulfilled并执行成功逻辑
 if (self.status === PENDING) {
 setTimeout(function() {
 self.status = FULFILLED;
 self.value = value;
 self.onFulfilled(self.value);
 })
 }
 }
 function reject(error) {
 //如果状态是pending才去修改状态为rejected并执行失败逻辑
 if (self.status === PENDING) {
 setTimeout(function() {
 self.status = REJECTED;
 self.error = error;
 self.onRejected(self.error);
 })
 }
 }
 fn(resolve, reject);
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
 if (this.status === PENDING) {
 this.onFulfilled = onFulfilled;
 this.onRejected = onRejected;
 } else if (this.status === FULFILLED) {
 //如果状态是fulfilled,直接执行成功回调,并将成功值传入
 onFulfilled(this.value)
 } else {
 //如果状态是rejected,直接执行失败回调,并将失败原因传入
 onRejected(this.error)
 }
 return this;
}
module.exports = MyPromise

首先,我们建立了三种状态"pending","fulfilled","rejected",然后我们在reslove和reject中做判断,只有状态是pending时,才去改变promise的状态,并执行相应操作,另外,我们在then中判断,如果这个promise已经变为"fulfilled"或"rejected"就立刻执行它的回调,并把结果传入。

总结

以上就是Promise其中部分功能的简单实现,如果有同学想要更深入的了解的话,可以去网上或者官网查阅,其中包括了链式操作、串行异步任务等等功能的源码。

ICP备案号:苏ICP备14035786号-1 苏公网安备 32050502001014号