Promise
Promise 对象用于表示异步操作的最终完成或失败及其结果,Promise 构造函数接收(resolve, reject) => void函数对象。在实例化后会立刻执行该函数函数,并且保证异步的返回函数的执行结果。
Promise 的then方法可以实现链式调用,相对于callback可以实现更加优异的异步操作状态管理,避免代码陷入回调地狱。
基本用法
Promise 对象是一个构造函数,用来生成 Promise 实例,参数是(resolve, reject) => void形式的函数,resolve和reject是函数。
Promise 实例有三种状态,调用resolve和reject函数可以改变实例的状态,实例的状态转换是不可逆的:
- 进行中(Pending):实例初始状态,Promise 对象创建后会立即开始执行传入的函数,实例初始状态为
Pending。 - 已完成(Resolved):在函数内调用
resolve方法后,实例状态转换为Resolved - 已失败(Rejected):在函数内调用
reject方法或者在有异常抛出后,实例状态转换为Rejected
var promise = new Promise(function(resolve, reject){
if (somethingTrue) {
resolve(value);
} else {
reject(err);
}
});
promise.then(
(value) => {
// success
return data;
}, (err) => {
// fail
}
).then((value) => {}, (err) => {}); // 链式调用
使用实例的then()方法可以指定 Resolved 和 Rejected 的回调函数,then()方法会返回一个新的 Promise 对象,所有可以实现链式调用,需要注意:
- 异步任务执行完成之后不会立刻执行回调函数,会在本轮事件循环之后调用,详见JavaScript 运行机制
then回调函数即使是在异步任务执行完成之后添加也可以被调用,并且不限制调用次数- 多次调用
then可以添加多个回调函数,并且会按照插入顺序执行 then回调函数的返回值可以在下一个then回调函数接受- 透传:当
then方法未定义回调函数,Promise 会使用内部默认的定义的方法,将结果传递给下一个then then回调函数中抛出异常会在调用链的下一个cache方法中捕获,在捕获之前的then方法会跳过cache方法后的then方法还会被继续调用
const p = new Promise((resolve, reject) => {
resolve(123);
});
p.then((value) => {
console.log('first then', value)
return 456;
}).then((value) => {
console.log('first then.then', value)
})
// 输出顺序
// first then, 123
// second then, 123
p.then((value) => {
console.log('second then', value)
throw 'test error'
}).then((value) => {
// 会被跳过
console.log(value)
}, (error) => {
console.log('second then.cache', error)
return 'error fixed'
}).then((value) => {
console.log(value)
})
// second then 123
// second then.cache, test error
// error fixed
注意:调用resolve或者reject方法更新实例状态后,并不会终止函数内部剩余代码执行
实例方法
Promise.prototype.then(successCallback, failureCallback): Promise:Promise 实例状态改变后的回调函数successCallback:Resolved 状态回调函数,可选参数,默认(value) => valuefailureCallback:Rejected 状态回调函数,可选参数,默认(error) => throw error- 返回值:一个新的 Promise 实例
Promise.prototype.catch(failureCallback):是.then(null, failureCallback)的简写,用于指定错误时的回调函数- 参数:
failureCallback:Rejected 状态回调函数 - 返回值:一个新的 Promise 实例
- 参数:
Promise.prototype.finally(onFinally):在 promise 结束时,无论结果是resolved或者是rejected,都会执行指定的回调函数- 参数:
onFinally:回调函数
- 参数:
静态方法
Promise.resolve(value):返回一个状态为resolved的 Promise 实例Promise.reject(reason):返回一个状态为rejected的 Promise 实例Promise.all(iterable):将多个 Promise 实例包装成一个 Promise 实例- 参数:
iterable:Promise iterable 类型数据 - 返回值:一个新的 Promise 实例
- 只有参数中所有的实例都为
resolved,返回实例的状态才为resolved,返回值为全部实例返回值的数组 - 只要参数中有一个实例的状态为
rejected,返回实例的状态即为rejected,返回值为第一个rejected实例的值
- 只有参数中所有的实例都为
- 参数:
Promise.allSettled(iterable):类似Promise.all(),区别不关心每个实例的状态,等全部实例对象状态确认后返回一个数组对象,对应每个实例的结果。Promise.race(iterable):将多个 Promise 实例包装成一个 Promise 实例- 参数:
iterable:Promise iterable 类型数据 - 返回值:一个新的 Promise 实例,只要实例数组中有一个实例的状态改变,返回实例的状态就改变,值为第一个改变实例的值
- 参数:
Promise.any(iterable):类似Promise.race(),区别是等到第一个resolved的实例并返回
异常处理
如果 Promise 在执行过程中抛出异常或被 reject,但没有提供 .catch() 进行错误捕获,就会产生 未处理的 Promise 拒绝(Unhandled Promise Rejection)。
- 浏览器会在控制台输出 Unhandled Promise Rejection 的警告,并可能终止代码的执行。
- 在 Node.js 中,如果 Promise 被 reject 但没有 catch 处理,默认情况下会触发 unhandledRejection 事件,并可能导致进程崩溃
process.on('uncaughtException', (error: any) => {
logger.error('uncaughtException', error)
})
// 在 Node.js 或浏览器环境中,可以监听 未处理的 Promise 错误,避免进程崩溃:
process.on('unhandledRejection', (error: any) => {
logger.error('unhandledRejection', error)
})
window.onerror = function (message, source, lineno, colno, error) {
reportError({ type: "runtime", message, source, lineno, colno, error });
};
window.onunhandledrejection = function (event) {
reportError({ type: "promise", message: event.reason });
event.preventDefault(); // 可阻止默认的错误日志输出(不推荐)
};
function reportError(error) {
fetch("https://example.com/error-report", {
method: "POST",
body: JSON.stringify(error),
headers: { "Content-Type": "application/json" },
});
}