# 从零开始实现一个Promise
先看看promise的一个基本用法:
function task1() {
return new Promise(function(resolve, reject) {
console.log("task1");
})
}
function task2() {
return new Promise(function(resolve, reject) {
console.log("task2");
})
}
function task3() {
return new Promise(function(resolve, reject) {
console.log("task3");
})
}
// 调用函数
task1()
.then(task2())
.then(task3())
创建Promise实例时,我们传入了一个函数,函数的两个参数(resolve/reject)分别将Promise的状态变为成功态和失败态。首先搭建出基本骨架:
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class Promise {
constructor(executor) {
this.state = PENDING
this.value = undefined
this.reason = undefined
}
resolve(value) {
}
reject(reason) {
}
}
Promise.prototype.then = (onFullFilled, onRejected) => {
}
module.exports = Promise
Promise实例中state保存它的状态,分为3种:等待态(pending)成功态(resolved)和失败态(rejected)。因为Promise也可以通过.then进行调用,因此在Promise的原型上绑定了then方法。
接下来分别实现:
- 当实例化Promise时,构造函数中就要马上调用传入的executor函数执行
- 完成resolve和reject方法,已经是成功态或是失败态不可再更新状态
- 实现原型上的then方法,完成Promise.prototype.then函数
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class Promise {
constructor(executor) {
this.state = PENDING
this.value = undefined
this.reason = undefined
executor(this.resolve, this.reject)
}
resolve(value) {
if (this.state === PENDING) {
this.value = value
this.state = RESOLVED
}
}
reject(reason) {
if (this.state === PENDING) {
this.reason = reason
this.state = REJECTED
}
}
}
Promise.prototype.then = (onFullFilled, onRejected) => {
if (this.state === RESOLVED) {
if (typeof onFullFilled === 'function') {
onFullFilled(this.value)
}
}
if (this.state === REJECTED) {
if (typeof onRejected === 'function') {
onRejected(this.reason)
}
}
}
module.exports = Promise
目前已经完成了Promise的基本功能,接下来解决异步问题。因为此时的代码还不支持Promise种传入异步函数。 我们可以创建两个数组onFulfilledFunc、onRejectedFunc 分别存放成功的回调和失败的回调,当then方法执行时,若状态还在等待态(pending),将回调函数依次放入数组中,这样在resolve和reject方法中可以分别将数组中的回调函数依次执行(resolve中执行onFulfilledFunc的所有方法,reject中执行onRejectedFunc的所有方法),具体实现如下:
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class Promise {
constructor(executor) {
this.state = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFunc = []; //保存成功回调
this.onRejectedFunc = []; //保存失败回调
executor(this.resolve, this.reject)
}
resolve(value) {
if (this.state === PENDING) {
this.value = value
this.onFulfilledFunc.forEach(fn => fn(value))
this.state = RESOLVED
}
}
reject(reason) {
if (this.state === PENDING) {
this.reason = reason
this.onRejectedFunc.forEach(fn => fn(reason))
this.state = REJECTED
}
}
}
Promise.prototype.then = (onFullFilled, onRejected) => {
if (this.state === PENDING) {
if (typeof onFulfilled === 'function') {
this.onFulfilledFunc.push(onFulfilled); //保存回调
}
if (typeof onRejected === 'function') {
this.onRejectedFunc.push(onRejected); //保存回调
}
}
if (this.state === RESOLVED) {
if (typeof onFullFilled === 'function') {
onFullFilled(this.value)
}
}
if (this.state === REJECTED) {
if (typeof onRejected === 'function') {
onRejected(this.reason)
}
}
}
module.exports = Promise
现在我们测试实现的Promise类:
function task1() {
return new Promise(function(resolve, reject) {
console.log("task1");
})
}
function task2() {
return new Promise(function(resolve, reject) {
console.log("task2");
})
}
function task3() {
return new Promise(function(resolve, reject) {
console.log("task3");
})
}
// 调用函数
task1()
.then(task2())
.then(task3())
-----------------------
output:
task1
task2
task3
不过目前的Promise还存在一些问题:
- 尚不支持then链式调用
- 异常捕获
- all、race等方法实现
接下来实现链式调用和异常捕获:
- 每个then方法都返回一个新的Promise对象(原理的核心)
- 如果then方法中显示地返回了一个Promise对象就以此对象为准,返回它的结果
- 如果then方法中返回的是一个普通值(如Number、String等)就使用此值包装成一个新的Promise对象返回。
- 如果then方法中没有return语句,就视为返回一个用Undefined包装的Promise对象
- 若then方法中出现异常,则调用失败态方法(reject)跳转到下一个then的onRejected
- 如果then方法没有传入任何回调,则继续向下传递(值的传递特性)。
修改如下:
- 使MyPromise.prototype.then方法返回一个Promise
- 实现resolvePromise方法(核心)
- 重写MyPromise.prototype.then逻辑
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.state = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFunc = []; //保存成功回调
this.onRejectedFunc = []; //保存失败回调
executor(this.resolve, this.reject)
}
resolve(value) {
if (this.state === PENDING) {
this.value = value
this.onFulfilledFunc.forEach(fn => fn(value))
this.state = RESOLVED
}
}
reject(reason) {
if (this.state === PENDING) {
this.reason = reason
this.onRejectedFunc.forEach(fn => fn(reason))
this.state = REJECTED
}
}
}
/**
* 解析then返回值与新Promise对象
* @param {Object} promise2 新的Promise对象
* @param {*} x 上一个then的返回值
* @param {Function} resolve promise2的resolve
* @param {Function} reject promise2的reject
*/
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Promise发生了循环引用'));
}
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
//可能是个对象或是函数
try {
let then = x.then;
if (typeof then === 'function') {
let y = then.call(x, (y) => {
//递归调用,传入y若是Promise对象,继续循环
resolvePromise(promise2, y, resolve, reject);
}, (r) => {
reject(r);
});
} else {
resolve(x);
}
} catch (e) {
reject(e);
}
} else {
//是个普通值,最终结束递归
resolve(x);
}
}
MyPromise.prototype.then = (onFullfilled, onRejected) => {
var promise2 = new Promise((resolve, reject) => {})
var self = this
if (this.state === PENDING) {
promise2 = new Promise(function(resolve, reject) {
if (typeof onFullFilled === 'function') {
self.onRejectedFunc.push(function() {
//x可能是一个promise,也可能是个普通值
setTimeout(function() {
try {
let x = onFullfilled(self.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
}
if (typeof onRejected === 'function') {
self.onRejectedFunc.push(function() {
//x可能是一个promise,也可能是个普通值
setTimeout(function() {
try {
let x = onRejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
}
})
}
if (this.state === RESOLVED) {
if (typeof onFullFilled === 'function') {
promise2 = new Promise(function(resolve, reject) {
//x可能是一个promise,也可能是个普通值
setTimeout(function() {
try {
let x = infulfilled(self.value)
onFullFilled(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
}
}
if (this.state === REJECTED) {
if (typeof onRejected === 'function') {
promise2 = new Promise(function(resolve, reject) {
//x可能是一个promise,也可能是个普通值
setTimeout(function() {
try {
let x = onRejected(self.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
});
})
}
}
return promise2
}
module.exports = MyPromise