Skip to main content

Promise

实现 promise

主要把握以下几个要点:

  • 状态控制
  • 链式调用
  • 异常处理
function Promises(fn) {
let self = this;
self.status = "pending"; // 状态
self.values = undefined; // 成功时的值
self.reason = undefined; // 失败时的值
function resolve(value) {
if (self.status === "pending") {
// 只允许pending到其他两个状态的转变
self.value = value;
self.status = "resolved";
}
}
function reject(reason) {
if (self.status === "pending") {
// 只允许pending到其他两个状态的转变
self.value = value;
self.status = "rejected";
}
}
try {
fn(resolve, reject);
} catch (e) {
console.log(e);
}
}

Promise.prototype.then = function (onFullfilled, onRejected) {
let self = this;
switch (self.status) {
case "resolved":
onFullfilled(self.value);
break;
case "rejected":
onRejected(self.reason);
break;
default:
}
};

let test = new Promise(function (resolve, reject) {
resolve(1);
});
test.then(function (x) {
console.log(x);
});

完整版

const PENDING = "PENDING",
FULFILLED = "FULFILLED",
REJECTED = "REJECTED"; // 三种状态

class MyPromise {
constructor(executor) {
// 实例化时传参:executor 执行器
this.status = PENDING;
this.value = undefined;
this.reason = undefined;

this.onFulfilledCallbacks = []; // 订阅池
this.onRejectedCallbacks = [];

const resolve = (value) => {
// 处理 resolve 传入的值也是 Promise 的情况
if (value instanceof MyPromise) {
value.then(resolve, reject);
return; // 递归调用,阻止向下继续执行
}

if (this.status === PENDING) {
// 必须得在 status 为 PENDING 状态下时,才能改变状态
this.status = FULFILLED;
this.value = value;

// 发布
this.onFulfilledCallbacks.forEach((fn) => fn());
}
};

const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;

// 发布
this.onRejectedCallbacks.forEach((fn) => fn());
}
};

try {
executor(resolve, reject);
} catch (err) {
// 如果在 executor 中直接抛出错误,得用 try-catch 捕获下,并走 reject
reject(err);
}
}

then(onFulfilled, onRejected) {
// 防止 .then() 不传参
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
// then 每次都返回一个新的 Promise
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
// onFulfilled 有可能返回一个普通值,也有可能返回一个 Promise
// 所以需要一个函数来判断和处理这个返回值 x
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
}
if (this.status === PENDING) {
// 订阅
this.onFulfilledCallbacks.push(() => {
// PENDING状态下回调也要异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
}, 0);
});
}
});
return promise2;
}

// catch() 相当于.then(null, () => {})
catch(errorCallback) {
return this.then(null, errorCallback);
}

// 1. finally 无论外边的Promise成功还是失败,都要走finally的回调,并且回调不带参数
// 2. finally 不返回 Promise 时, 走 then 或者 catch 取决于外边 Promise
// 3. 如果 finally 内部有 promise 并且有延迟处理,整个finally会等待
// 4. finally的promise如果是reject,优先级更高
// 5. finally的promise如果是resolve,则外边优先级更高
finally(finallyCallback) {
// finally是实例方法,得 return this.then
return this.then(
(value) => {
// finally 能执行异步,所以 return 一个 MyPromise.resolve
// finally 本身没有状态
// 所以执行完cb后,再调用 then 返回 finally 之前的 resolve 情况下的 value
return MyPromise.resolve(finallyCallback()).then(() => value);
},
(reason) => {
// onRejected也得调用 MyPromise.resolve
// 因为 finally本身不影响外边的状态
// 在 finally 中return Promise 且 返回 rejected 的情况下
// MyPromise.resolve一个rejected的Promise,最终状态也会是这个新的Promise的rejected状态
return MyPromise.resolve(finallyCallback()).then(() => {
throw reason;
});
}
);
}

// Promise 的 静态方法 resolve、reject
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}

return new MyPromise((resolve, reject) => {
resolve(value);
});
}

static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}

static all(promiseArr) {
let resArr = [],
count = 0;

return new MyPromise((resolve, reject) => {
promiseArr.map((promise, index) => {
if (isPromise(promise)) {
promise.then((value) => {
formatResArr(value, index, resolve);
}, reject);
} else {
formatResArr(promise, index, resolve);
}
});
});

// value是返回值,index是数组索引,resolve是回调
function formatResArr(value, index, resolve) {
resArr[index] = value; // 保证结果和数组顺序一致

if (++count === promiseArr.length) {
// 保证全部结果都成功返回后再返回最终结果
resolve(resArr);
}
}
}

static allSettled(promiseArr) {
if (!isIterator(promiseArr)) {
throw new TypeError(
promiseArr +
" is not iterable (cannot read property Symbol(Symbol.iterator))"
);
}

let resArr = [],
count = 0;

return new MyPromise((resolve, reject) => {
// 数组为空的时候,返回空数组
if (promiseArr.length === 0) {
resolve([]);
} else {
promiseArr.map((promise, index) => {
if (isPromise(promise)) {
promise.then(
(value) => {
formatResArr("fulfilled", value, index, resolve);
},
(reason) => {
formatResArr("rejected", reason, index, resolve);
}
);
} else {
formatResArr("fulfilled", promise, index, resolve);
}
});
}
});

function formatResArr(status, value, index, resolve) {
switch (status) {
case "fulfilled":
resArr[index] = {
status,
value,
};
break;
case "rejected":
resArr[index] = {
status,
reason: value,
};
break;
default:
break;
}
if (++count === promiseArr.length) {
resolve(resArr);
}
}
}

static race(promiseArr) {
return new MyPromise((resolve, reject) => {
if (promiseArr.length === 0) {
resolve();
} else {
promiseArr.map((promise) => {
// if (isPromise(promise)) {
// promise.then(resolve, reject);
// } else {
// resolve(promise);
// }
MyPromise.resolve(promise).then(resolve, reject);
});
}
});
}
}

// 判断是否为 Promise
function isPromise(x) {
if ((typeof x === "object" && x !== null) || typeof x === "function") {
let then = x.then;
return typeof then === "function";
}
return false;
}

// 判断是否为可迭代对象
function isIterator(value) {
return (
value !== undefined &&
value !== null &&
typeof value[Symbol.iterator] === "function"
);
}

function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError("Chaining cycle detected for promise #<MyPromise>"));
}

let called = false; // 防止 resolve、reject 都调用的情况

if ((typeof x === "object" && x !== null) || typeof x === "function") {
try {
// 防止 then 抛错 throw Error
let then = x.then;

if (typeof then === "function") {
// 认定为 Promise
then.call(
x,
(y) => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (err) {
if (called) return;
called = true;
reject(err);
}
} else {
resolve(x);
}
}

MyPromise.defer = MyPromise.deferred = function () {
let deferred = {};

deferred.promise = new MyPromise((resolve, reject) => {
deferred.resolve = resolve;
deferred.reject = reject;
});

return deferred;
};

module.exports = MyPromise;

实现 all/allSetteld

all

Promise.prototype.all = function (promises) {
let results = [];
let promiseCount = 0;
let promisesLength = promises.length;
return new Promise(function (resolve, reject) {
promises.forEach(function (val, i) {
// 可能不是promise实例,需要先转换
Promise.resolve(val).then(
function (res) {
promiseCount++;
results[i] = res;
if (promiseCount === promisesLength) {
return resolve(results);
}
},
function (err) {
return reject(err);
}
);
});
});
};

allSettled

Promise.MyAllSettled = function (promises) {
let arr = [],
count = 0;
return new Promise((resolve, reject) => {
promises.forEach((item, i) => {
Promise.resolve(item).then(
(res) => {
arr[i] = { status: "fulfilled", val: res };
count += 1;
if (count === promises.length) resolve(arr);
},
(err) => {
arr[i] = { status: "rejected", val: err };
count += 1;
if (count === promises.length) resolve(arr);
}
);
});
});
};

实现 any/race

race

Promise.MyRace = function (promises) {
return new Promise((resolve, reject) => {
for (const item of promises) {
Promise.resolve(item).then(resolve, reject);
}
});
};

any

Promise.MyAny = function (promises) {
let arr = [],
count = 0;
return new Promise((resolve, reject) => {
promises.forEach((item, i) => {
Promise.resolve(item).then(resolve, (err) => {
arr[i] = { status: "rejected", val: err };
count += 1;
if (count === promises.length) reject(new Error("没有promise成功"));
});
});
});
};