手写实现PromiseA+规范
1. 什么是promise
在以往我们处理多个JS请求的时候汪汪都是多个回调函数嵌套使用,使得代码难以阅读和维护,所以为了解决这个问题我们引入了新的异步解决方案就是Promise
抽象表达: Promise就是JS中的新的异步解决方案
具体表达: Promise就是一个构造函数,自身有all,race,resolve,reject等方法,原型上有then,catch方法
promise基础知识 promise基本使用
2. 手写实现PromiseA+规范
首先我们了解下promise基本使用
const p = new Promise((resolve, reject) => {
resolve("success");
})
p.then(value => {
console.log(value)
}, reason => {
console.log(reason)
}
)
然后基于Promise/A+规范(英文),中文我们实现
实现代码,包括常用api
//定义状态变量
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise {
constructor(executor) {
this.status = PENDING;
//存放成功的值
this.value = undefined;
//存放失败的值
this.reason = undefined;
//存放回调函数
this.callbacks = [];
//调用此方法就是成功
let resolve = (value) => {
//如果第一个Promise传值就是一个Promise实例
if (value instanceof Promise) {
return value.then(resolve, reject);
}
//状态为pending时才能改变状态
if (this.status !== PENDING) {
return;
}
//修改状态
this.status = FULFILLED;
//保存成功的值
this.value = value;
//resolve异步执行的时候在调用已经保存的回调函数,这里涉及到设计模式 发布订阅模式 依赖收集 -- 等待触发 -- 执行依赖
if (this.callbacks.length > 0) {
this.callbacks.forEach((callbackObj) => {
callbackObj.onFulfilled(this.value);
})
}
}
let reject = (reason) => {
//状态为pending时才能改变状态
if (this.status !== PENDING) {
return;
}
this.status = REJECTED;
this.reason = reason;
if (this.callbacks.length > 0) {
this.callbacks.forEach((callbackObj) => {
callbackObj.onRejected(this.reason);
})
}
}
//立即执行构造器函数,如果执行有异常就会直接调用reject
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
//then 方法实现
then(onFulfilled, onRejected) {
//保证值的传递
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
//异常穿透的关键
onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason };
//then调用返回一个promise
const promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
//执行onFulfilled
let result = onFulfilled(this.value);
//处理promise对象返回,处理嵌套的promise对象,然后兼容其他类库的promise实现
resolvePromise(result, promise2, resolve, reject);
} catch (error) {
reject(error)
}
})
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let result = onRejected(this.reason);
resolvePromise(result, promise2, resolve, reject);
} catch (error) {
reject(error)
}
})
}
//满足异步执行resolve/reject情况
if (this.status === PENDING) {
this.callbacks.push({
onFulfilled: () => {
setTimeout(() => {
try {
let result = onFulfilled(this.value);
resolvePromise(result, promise2, resolve, reject);
} catch (error) {
reject(error)
}
})
},
onRejected: () => {
setTimeout(() => {
try {
let result = onRejected(this.reason);
resolvePromise(result, promise2, resolve, reject);
} catch (error) {
reject(error)
}
})
}
})
}
})
return promise2;
}
catch(onRejected){
return this.then(undefined, onRejected);
}
//Promise.resolve方法
static resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
})
}
//Promise.reject方法
static reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
//Promise.all方法
static all = function (promiseArr) {
let length = promiseArr.length;
let resolveArr = new Array(length);
let resolveCount = 0; //返回成功的个数
return new Promise((resolve, reject) => {
promiseArr.forEach((promiseItem, index) => {
Promise.resolve(promiseItem).then(
value => {
resolveCount++;
resolveArr[index] = value;
if (length === resolveCount) {
resolve(resolveArr);
}
},
reject
)
})
})
}
//Promise.race方法
static race = function(promiseArr){
return new Promise((resolve, reject) => {
promiseArr.forEach((promiseItem) => {
Promise.resolve(promiseItem).then(resolve, reject);
})
})
}
}
//实现链式调用,值穿透
function resolvePromise(result, promise2, resolve, reject) {
//对返回的 result 进行判断得出返回的promise状态
/*
1.如果抛出异常就返回失败的promise,value为异常
2. 如果为非promise的基本类型,返回成功的promise ,value就为该基本类型
3. 如果为promise对象,返回的promise结果就为该promise的结果
4. 如果为thenable类型,即有then函数或者属性的函数或者对象,所以为函数就执行该对象或者函数的then,不为就以该类型作为参数执行promise
*/
//避免循环调用等待
if (result === promise2) {
return reject(new TypeError('chaining cycle detected for promise!'))
}
//严格判断类型
if (result && (typeof result === 'object' || typeof result === 'function')) {
let called;//判断调用过resolve/reject没,防止重复调用
try {
//tyrcatch保证调用其他库的promise或者thenable 设置了then不能被调用而导致报错(Object.defineProperty)
let then = result.then;
if (typeof then === 'function') {
//这样保证有些库设置了then可取的个数,比如设置了Object.defineProperty 比如 第一次then=result.then后再 then=result.then就报错
then.call(result, value => {
if (called) return;
called = true;
resolvePromise(value, promise2, resolve, reject);
//resolve(value)
}, reason => {
if (called) return;
called = true;
reject(reason);
});
} else {
resolve(result);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(result);
}
}
module.exports = Promise;
3. 测试是否满足PromiseA+规范
下载测试工具
npm i promises-aplus-tests -g
将如下代码加到实现的Promise.js 文件中
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
运行命令
promises-aplus-tests [Promise.js文件名]