JS 代码是单线程执行的。如果全部都是同步操作,意味着在执行到网络请求和浏览器事件时,程序会阻塞直到网络请求完成或者浏览器事件发生。网络请求在经过一段时间后尚且会返回结果,但是浏览器事件完全依赖于用户的操作,将浏览器事件设为同步显然是错误的。难道用户不触发某个事件,程序就永不执行了吗?
JS 中所有网络请求和浏览器事件都必须是异步的。用于执行异步功能的程序叫做 回调函数。
ES6 规范了 Promise
对象,用来执行异步操作。
在主线程中,直接调用异步程序,获取异步程序返回的一个“承诺的”结果,即 Promise
对象。
const promise = new Promise((resolve, reject) => {
const timeOut = Math.random() * 2;
console.log('set timeout to: ' + timeOut + ' seconds.');
setTimeout(function () {
if (timeOut < 1) {
console.log('call resolve()...');
resolve('200 OK');
}
else {
console.log('call reject()...');
reject('timeout in ' + timeOut + ' seconds.');
}
}, timeOut * 1000);
})
声明一个 Promise
对象即执行一个异步程序,程序执行成功调用 resolve
方法,执行失败调用 reject
方法,并将对应参数传递给 resolve
或者 reject
方法。
声明 Promise
对象后,我们可以在将来的任意一个时刻获取这个“承诺”的结果。这个结果可能是成功的,也可能是失败的。如果我们在初始化 Promise
对象时对失败进行了显示处理,即显示调用了 reject
方法,在将来获取结果时也需要显示调用对错误结果的处理程序,即 onReject
函数,或者通过 .catch
方法对错误结果进行捕获。
使用 .then
方法来获取异步执行的结果,该方法需要一个或者两个函数来分别对成功和失败的异步任务结果进行处理:
promise.then(onResolve)
promise.then(onResolve, onReject)
如果在初始化 Promise
对象时对失败进行了显示处理,可以通过 onReject
方法处理错误结果,或者通过 promise.then(onResolve).catch(onReject)
来捕获错误结果。
onResolve
方法能够接收初始化 Promise
对象时调用 resolve
方法传入的参数;onReject
方法能够接收初始化 Promise
对象时调用 reject
方法传入的参数。
在异步执行时,Promise 将异步程序的执行和对结果的处理进行分离:
Promise 串行执行任务:
new Promise(function(resolve, reject) {
/* ... */
}).then(function() {
return new Promise(function(resolve, reject) {
/* ... */
})
}).then(function() {
return new Promise(function(resolve, reject) {
/* ... */
})
}).catch(function() {
/* ... */
})
并行执行异步任务直到所有子任务执行完毕:
const p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'P1')
})
const p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 600, 'P2')
})
Promise.all([p1, p2]).then(function(results) {
console.log(results)
// => ['P1', 'P2']
})
当其中一个子任务执行完成时结束异步任务:
Promise.race([p1, p2]).then(function(result) {
console.log(result)
// => 'P1'
})
Promise 的基本用法:
new Promise((resolve, reject) => void)
新建一个 Promise
对象。
Promise.all(promiseList)
异步执行所有子任务。
Promise.race(promiseList)
只返回执行最快的子任务结果。
评论区