重要代码
- asap 是一个封装了微任务包;网上百度到源码基本用:setTimeout(()=>{}, 0)
- 重点理解
- Promise 构造函数中 resolve、reject
- then 方法
- resolvePromise
const REJECTED = "REJECTED";
const FULFILLED = "FULFILLED";
const PENDING = "PENDING";
const resolvePromise = (promise2, x) => {
const { resolve, reject } = promise2;
if (promise2 === x)
return reject(
new TypeError("Chaining cycle detected for promise #<Promise>")
);
if ((typeof x === "object" && x !== null) || typeof x === "function") {
let called;
try {
const then = x.then;
if (typeof then !== "function") resolve(x);
else {
then.call(
x,
(y) => {
if (called) return;
called = true;
resolvePromise(promise2, y);
},
(f) => {
if (called) return;
called = true;
reject(f);
}
);
}
} catch (err) {
if (called) return;
called = true;
reject(err);
}
} else {
resolve(x);
}
};
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (value instanceof Promise) {
return value.then(resolve, reject);
}
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 (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (val) => val;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw err;
};
const promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
asap(() => {
promise2.resolve = resolve;
promise2.reject = reject;
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x);
} catch (err) {
reject(err);
}
});
}
if (this.status === REJECTED) {
asap(() => {
promise2.resolve = resolve;
promise2.reject = reject;
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x);
} catch (err) {
reject(err);
}
});
}
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
asap(() => {
promise2.resolve = resolve;
promise2.reject = reject;
try {
const x = onFulfilled(this.value);
resolvePromise(promise2, x);
} catch (err) {
reject(err);
}
});
});
this.onRejectedCallbacks.push(() => {
asap(() => {
promise2.resolve = resolve;
promise2.reject = reject;
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x);
} catch (err) {
reject(err);
}
});
});
}
});
return promise2;
}
catch(errCallback) {
return this.then(null, errCallback);
}
}
Promise 中方法作用
- resolve/reject:将 PENDING 状态修改 FULFILLED/REJECTED
- 根据 this.status 状态,向微任务队列添加微任务
- resolvePromise:then 中的回调函数执行完后,修改 pending 的状态
预备知识点
- 任务分为同步任务和异步任务;当同步任务执行完后,才执行异步任务
- 异步任务分为 微任务 和 宏任务;微任务在宏任务之前执行
- 常见的微任务:Promise(js 引擎)
- 宏任务:setTimeout(运行环境:浏览器、node)
题目
console.log(1);
const promise = new Promise((resolve) => {
console.log(2);
resolve(3);
console.log(4);
});
console.log(5);
promise
.then((data) => {
console.log(data);
setTimeout(() => console.log(6), 0);
return 7;
})
.then((data) => {
console.log(data);
});
setTimeout(() => console.log(8), 0);
console.log(9);
解析
- 输出 1(先执行同步任务)
- 输出 2
- 构造函数是同步任务;promise 构造函数执行了传进来的函数
- 输出 4
- 输出 5
- 输出 9
- 第一个 then 方法:
- resolve(3)将 PENDING 改成 FULFILLED
- 走 if(this.status === FULFILLED) 的判断,里面只有一个微任务执行函数(添加到微任务队列中)
- 第二个 then 方法:
- 没有执行 resolve 或 reject 其中一个方法,此时还是 PENDING
- 将 then 中的传入的方法添加到上一个 then 中的 onResolvedCallbacks 数组中
- 输出 3
- resolve(3): 只是改变当前状态:pending -> fulfilled,this.value = 3
- this.then(...)时,将执行 then 中的函数并传入 this.value 的值
- setTimeout(...)放到宏任务队列中
- 返回 7
- 输出 7
- 输出 8
- 微任务队列执行完毕后,开始执行宏任务队列
- 8 比 6 先进队列;根据队列特性:先进先出
- 输出 6
网上资料
- 以上讲解采用的 Promise 全部代码
- 谈谈 promise,谈谈微任务
- 手写 Promise