一、基础版本
目标
- 可以创建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对象添加回调函数,也会立即得到这个结果。
目标
- 实现promise的三种状态。
- 实现promise对象的状态改变,改变只有两种可能:从pending变为fulfilled和从pending变为rejected。
- 实现一旦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其中部分功能的简单实现,如果有同学想要更深入的了解的话,可以去网上或者官网查阅,其中包括了链式操作、串行异步任务等等功能的源码。