手写实现一个Promise
开发中 promise 的使用频率还是很高的,面试中几乎也是必考的。在这边记录一下如何自己手写实现一个 promise。原生的ES6自带了 promise ,不用考虑兼容性。
实现 Promise
- Promise 是一个类,在使用的时候,需要 new 这个类
- 在 new Promise 的时候,需要传入一个 executor 执行器,默认会立即被调用,且参数有两个(resolve ,reject)
- Promise 有3种状态,pendding 默认等待状态,onFulfilled 成功态,onRejected 失败态。(promise默认就是 pendding ,当用户调用 resolve 时会变成成功态 ,调用 reject 的时候会变成失败态。成功可以传入成功的原因,失败可以传入失败的原因 )
- new Promise 会返回一个 promise 实例,这个实例上有一个 then 方法,then 方法中有两个参数,一个是成功的回调一个是失败的回调。
- 走向失败有两种情况 ,1.reject() 2.用户主动抛出异常
- 一个 promise 中可以 then 多次(发布订阅模式)
- promise 的状态是不能从成功变成失败,也不能从失败变成成功,只有 pendding 的时候才能更改状态
function resolvePromise(x, promise2, resolve, reject) {
// x 决定promise2 的状态 走成功还是失败
if (promise2 === x) {
return reject(new TypeError("循环引用"));
}
// 判断x 是不是一个promise 先保证x 得是一个对象或者函数,如果不是对象或者函数那么x 一定不是promise
if ((typeof x === "object" && x !== null) || typeof x === "function") {
let called;
// 需要看 这个x 上有没有then方法 有then方法才说明他是一个promise
try {
let then = x.then; // x可能是别人写的promise 那么取then有风险,
if (typeof then === "function") {
then.call(
x,
(y) => {
// x.then((y)=>{},r=>{}) 取then就会有风险
if (called) return;
called = true;
resolvePromise(y, promise2, resolve, reject); // 递归解析直到我们的y的值是一个普通值
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
// 没有then方法的都执行这里
resolve(x); // 只是一个对象而已 就是一个普通值
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// x 就是一个普通的值,直接把x 传递给promise2的成功即可
resolve(x);
}
}
class Promise{
constructor(executor) {
this.value = undefined; //成功的原因
this.reason = undefined; //失败的原因
this.status = PENDING; //状态
this.onResvoledCallbacks = []; //存放成功的回调
this.onRejectedCallbacks = []; //存放失败的回调
//成功
const resolve = (value) => {
// 如何判断是不是一个promise 主要看有没有then方法
if (value instanceof Promise) {
return value.then(resolve, reject);
}
if (this.status === "PENDDING") {
this.status = "FULFILLED";
this.value = value;
this.onResvoledCallbacks.forEach((fn) => fn());
}
};
//失败
const reject = (reason) => {
if (this.status === "PENDDING") {
this.status = "REJECTED";
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
// 有可能这个 onFulfilled, onRejected 是可选的
onFulfilled = typeof onFulfilled === "function" ? onFulfilled:
function (data) { return data;};
onRejected = typeof onRejected === "function" ? onRejected :
(err) => { throw err;};
let promise2 = new Promise((resolve, reject) => {
if (this.status === "FULFILLED") {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === "REJECTED") {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === "PENDDING") {
this.onResvoledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
}
Promise Api
1、Promise.all
- 参数:接受一个数组,数组内都是Promise实例
- 返回值:返回一个Promise实例,这个Promise实例的状态转移取决于参数的Promise实例的状态变化。当参数中所有的实例都处于resolve状态时,返回的Promise实例会变为resolve状态。如果参数中任意一个实例处于reject状态,返回的Promise实例变为reject状态。
static all(values) {
return new Promise((resolve, reject) => {
let times = 0;
function processMap(key, value) {
arr[key] = value;
if (++times === values.length) {
resolve(arr);
}
}
const arr = [];
for (let i = 0; i < values.length; i++) {
let val = values[i]; // 可能是promise 也有可能是普通值
let then = val && val.then;
if (typeof then === "function") {
then.call(
val,
(data) => {
// 获取成功的结果
processMap(i, data);
},
reject
);
} else {
processMap(i, val);
}
}
});
}
2、Promise.race
- 参数:接受一个数组,数组内都是Promise实例
- 返回值:返回一个Promise实例,这个Promise实例的状态转移取决于参数的Promise实例的状态变化。当参数中任何一个实例处于resolve状态时,返回的Promise实例会变为resolve状态。如果参数中任意一个实例处于reject状态,返回的Promise实例变为reject状态。
- 面试时常考察超时如何处理,以及和promise.all的区别。
3、Promise.finally
- 无论成功还是失败都执行,只要调用了就会执行
finally(cb) {
return this.then(
(y) => {
return Promise.resolve(cb()).then(() => y);
},
(r) => {
return Promise.resolve(cb()).then(() => {
throw r;
});
}
);
}
4、Promise.resolve
返回一个Promise实例,这个实例处于resolve状态。根据传入的参数不同有不同的功能:
- 值(对象、数组、字符串等):作为resolve传递出去的值
- Promise实例:原封不动返回
5、Promise.reject
返回一个Promise实例,这个实例处于reject状态。参数一般就是抛出的错误信息。