Promise详解
Event Loop 事件循环机制
JavaScript 是单线程语言,浏览器环境下的 JavaScript 代码执行依赖于浏览器提供的事件循环机制(Event Loop)。事件循环机制中包含以下两个队列:
- 宏队列:包含
script脚本、setTimeout、setInterval、I/O、UI rendering等 - 微队列:包含
Promise、MutationObserver等
- 宏队列:包含
简而言之,每次取出第一个宏任务执行前,都要将微队列清空
Promise 的基本使用
new Promise(executor)
executor执行器函数,内部逻辑是同步执行的- 接收
resolve和reject两个函数参数,resolve函数调用后promise变为成功状态,reject函数调用后变为失败状态。若是执行器中抛出了异常,变为失败状态 promise的状态只能改变一次
then(onFulfilled, onRejected)
then方法调用时,Web Api 创建一个处理器,当promise有结果状态,且then参数中指定了对应的回调函数后,对应的回调函数插入微队列中等待执行- 两个回调函数的默认值:
onFulfilled = value => value,onRejected = reason => { throw reason; } then方法的返回值为一个新的promise,其结果、状态由回调函数的返回值决定:- 回调函数返回一个
promise时,then返回的promise的结果状态,和回调函数返回的promise的结果状态相同。因此想中断promise链,可以在回调函数中返回一个pending的promise - 回调函数返回非
promise时,then返回的promise状态为成功,结果为回调函数的返回值 - 回调函数抛出任何值,
then返回的promise状态为失败,结果为回调函数抛出的值
- 回调函数返回一个
catch(onRejected)
catch方法是then方法的语法糖,相当于then(undefined, onRejected)
Promise.resolve(value)
value为promise时,直接返回,否则包装为一个成功的promise返回
Promise.reject(reason)
reason为promise时,直接返回,否则包装为一个失败的promise返回
Promise.all(array)
- 如果
array中每一项都成功,则返回一个数组,对应的值为成功的值 - 如果有一项为失败,则返回失败的值
- 如果有一项不为
promise,则在数组中原样返回
Promise.race(array)
- 返回
array中第一个完成的promise的结果
async 函数和 await 表达式
async 函数
- 返回值为
Promise对象,结果由async函数的返回值决定
await 表达式
- 如果表达式是
Promise对象,await返回其成功的值 - 如果
Promise可能会失败,则应放在try catch里捕获处理 - 如果表达式是其他值,
await直接返回 - 必须写在
async函数中
自定义 Promise
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
// 异常处理
try {
executor(this.resolve, this.reject);
} catch (error) {
this.reject(error);
}
}
status = PENDING;
value = undefined;
reason = undefined;
// 一个promise实例,then方法能多次调用,因此需要一个队列用于缓存
onFulfilled = [];
onRejected = [];
// 箭头函数,因为resolve函数是直接调用的,在class中使用箭头函数可以把this绑定到实例对象上
resolve = value => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 调用成功的回调
while (this.onFulfilled.length) {
this.onFulfilled.shift()(this.value);
}
}
};
reject = reason => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 调用失败的回调
while (this.onRejected.length) {
this.onRejected.shift()(this.reason);
}
}
};
// 普通函数,因为this已通过实例对象的调用而绑定
// 成功回调函数不传时默认为value => value
// 失败回调函数不传时默认为reason => { throw reason; }
then(
onFulfilled = value => value,
onRejected = reason => {
throw reason;
}
) {
// then方法返回一个promise实例对象,以支持链式调用
let returnPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// returnPromise在new Promise完成后才能获取到,因此使用setTimeout变为异步代码
setTimeout(() => {
// then的回调函数中异常处理
try {
// 下一个then方法的成功回调函数接收的值
let x = onFulfilled(this.value);
resolvePromise(returnPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.status === REJECTED) {
// returnPromise在new Promise完成后才能获取到,因此使用setTimeout变为异步代码
setTimeout(() => {
// then的回调函数中异常处理
try {
// 下一个then方法的失败回调函数接收的值
let x = onRejected(this.reason);
resolvePromise(returnPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
// 调用then时依然是pending状态,缓存成功和失败的回调
else {
this.onFulfilled.push(() => {
// returnPromise在new Promise完成后才能获取到,因此使用setTimeout变为异步代码
setTimeout(() => {
// then的回调函数中异常处理
try {
// 下一个then方法的成功回调函数接收的值
let x = onFulfilled(this.value);
resolvePromise(returnPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejected.push(() => {
// returnPromise在new Promise完成后才能获取到,因此使用setTimeout变为异步代码
setTimeout(() => {
// then的回调函数中异常处理
try {
// 下一个then方法的失败回调函数接收的值
let x = onRejected(this.reason);
resolvePromise(returnPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return returnPromise;
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
// 无论promise成功还是失败,都会调用
// 返回一个promise,可以获取到成功或失败的值
finally(callback) {
return this.then(
value => {
return MyPromise.resolve(callback()).then(() => value);
},
reason => {
return MyPromise.resolve(callback()).then(() => {
throw reason;
});
}
);
}
static all(array) {
return new MyPromise((resolve, reject) => {
// 计数器,当数组中有异步代码时,保证resolve方法在所有异步任务结束后才被调用
let count = 0;
let res = [];
for (let i = 0; i < array.length; i++) {
if (array[i] instanceof MyPromise) {
array[i].then(
value => {
res[i] = value;
count++;
if (count === array.length) {
resolve(res);
}
},
reason => {
reject(reason);
}
);
} else {
res[i] = array[i];
count++;
if (count === array.length) {
resolve(res);
}
}
}
});
}
static race(array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
array[i].then(
value => {
resolve(value);
},
reason => {
reject(reason);
}
);
}
});
}
static resolve(value) {
return value instanceof MyPromise ? value : new MyPromise(resolve => resolve(value));
}
static reject(reason) {
return reason instanceof MyPromise ? reason : new MyPromise(reject => reject(reason));
}
}
function resolvePromise(returnPromise, x, resolve, reject) {
// 如果x是promise实例,判断x的状态,决定调用resolve还是reject
if (x instanceof MyPromise) {
// 回调函数返回的promise,不能是then函数返回的promise
if (x === returnPromise) {
reject(new TypeError(''));
return;
}
x.then(
value => resolve(value),
reason => reject(reason)
);
} else {
resolve(x);
}
}Promise详解
https://www.reimu747.ink/post/20200508.html