3年没有出去面试了。最近出去转转,发现现在行情如此惨烈,上来就让手写一个promise。我想问的是,写的出来就一定能用到的好嘛?没办法,有时间抱怨面试太难,不如沉下心来,耐心解读。
promise规范解读
-
- new Promise时,需要传递一个executor执行器,执行器立即执行
-
- executor 接受两个参数,参数是函数,分别是resolve和reject
-
- promise 只能从pending到rejected,或者从pending到fulfilled
-
- promise 的状态一旦确认,就不会再改变
-
- promise都有then方法,then接收两个参数,分别是promise成功的回调onFulfilled,和promise失败的回调onRedjected
- 6.如果调用then时,promise已经成功,则执行onFulfilled并将promise的值作为参数传递进去。
- 如果promise已经失败那么执行onRejected,并讲promise失败的原因作为参数传递进去。
- 如果promise的状态是pending,需要将onFulfilled和onRejected函数存放起来,等待状态确定后。再依次将对应的函数执行(发布订阅)
- 7.then 的参数onFulfilled和onRejected可以缺省
- 8.promise可以then多次,promise的then返回一个新的promise
- 9.如果then返回的是一个结果,那么就会把这个结果作为参数,传递给下一个then的成功回调(onFulfilled)
- 10.如果then中抛出异常没那么就会把异常作为参数传递给下一个then的失败回调(onRejected)
- 11.如果then返回的是一个promise,那么会等这个promise执行完,promise成功就会走下一个then的成功,
- 如果失败就走下一个then的失败
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
let called;
if (x !== null && (typeof x === "object" || typeof x === "function")) {
try {
let then = x.then;
if (typeof then === "function") {
then.call(
x,
(y) => {
if (called) {
return;
}
called = true;
resolvePromise(promise2, y, resolve, reject);
},
(err) => {
if (called) {
return;
}
called = true;
reject(err);
}
);
} else {
resolve(x);
}
} catch (error) {
if (called) {
return;
}
called = true;
reject(error);
}
} else {
resolve(x);
}
}
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = "";
this.reason = "";
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.onResolvedCallbacks.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 (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw err;
};
const promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
}
});
return promise2;
}
catch(fn) {
return this.then(null, fn);
}
}
Promise.resolve = (val) => {
if (val instanceof Promise) {
return val;
}
return new Promise((resolve) => resolve(val));
};
Promise.reject = (val) => {
return new Promise((resolve, reject) => reject(val));
};
Promise.race = (promises) =>
new Promise((resolve, reject) =>
promises.forEach((pro) => pro.then(resolve, reject))
);
Promise.all = (promise) => {
return new Promise((resolve, reject) => {
let index = 0;
let result = [];
if (promise.length === 0) {
resolve(result);
} else {
const processValue = (i, data) => {
result[i] = data;
if (++index === promise.length) {
resolve(result);
}
};
for (let i = 0; i < promise.length; i++) {
Promise.resolve(promise[i]).then(
(data) => {
processValue(i, data);
},
(err) => {
reject(err);
return;
}
);
}
}
});
};
Promise.resolve("222222").then((res) => {
console.log(res);
});
Promise.reject("reject222222").catch((err) => {
console.log("reject", err);
});
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
const n = Math.random();
if (n > 0.5) {
resolve("p1 resolve 结果:" + n);
} else {
reject("p1 reject 结果:" + n);
}
}, 900);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
const n = Math.random();
if (n > 0.5) {
resolve("p2 resolve 结果:" + n);
} else {
reject("p2 reject 结果:" + n);
}
}, 600);
});
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
const n = Math.random();
if (n > 0.5) {
resolve("p3 resolve 结果:" + n);
} else {
reject("p3 reject 结果:" + n);
}
}, 1300);
});
Promise.resolve(p1).then((res) => {
console.log("Promise.resolve(p1)", res);
});
Promise.race([p1, p2, p3])
.then((res) => {
console.log("race", res);
})
.catch((err) => {
console.log("race", err);
});
Promise.all([p1, p2, p3])
.then((res) => {
console.log(`all res`, res);
})
.catch((err) => {
console.log("all catch", err);
});
以上内容参考了其他掘金文章,不具体说明了。