事件阻塞
由于js是单线程模式
,所有的js代码都在一个主线程上执行,当主线程正在执行一个长时间运行的操作时,它就无法同时处理其他事件的请求了,如果js是多线程,那么不同的线程可能会同时修改同一个变量,从而导致不可预料的结果。为了避免事件阻塞,采用异步编程的方式,使用异步API和回调函数来处理长时间运行的操作。
异步编程
的原理,将长时间运行的操作放到一个单独的线程中执行,在操作完成后,将结果传递给js主线程进行处理。这样可以避免长时间运行的操作阻塞js主线程,保证页面的响应性能。
Promise
Promise是一种用于异步编程的js对象,它可以解决回调地狱
的问题,并提供更好的代码可读性
和可维护性。Promise可以看作一种承诺
,表示在未来某个时间点会返回一个结果
,这个结果可以是成功的,也可以是失败的。
三种状态:
1、Pending(等待状态): Promise对象刚被创建时的初始状态,此时还没有返回结果。
2、Fulfilled(成功状态):当Promise对象返回结果时,进入成功状态,并把结果作为参数传递给后续的then方法。
3、Rejected(失败状态):当Promise对象返回错误结果时,进入失败状态,并把错误信息作为参数传递给后续的catch方法
API
- Promise.resolve()
- Promise.reject()
- Promise.prototype.then
- Promise.prototype.catch
- Promise.race
let downloadCancelled = false;
const cancelDownload = () => {
downloadCancelled = true;
};
const downloadFile = new Promise((resolve, reject) => {
// 下载大文件
});
const cancel = new Promise((resolve, reject) => {
while (!downloadCancelled) {
// 等待用户点击取消按钮
}
resolve('Download cancelled');
});
Promise.race([downloadFile, cancel]).then(result => {
console.log(result); // 下载已取消
}).catch(error => {
console.error(error); // 下载错误
});
- Promise.all
async/await
在promise异步编写方式进一步升级,更靠近同步编写方式
function ff (){
return new Promise((resolve,reject)=>{
....
})
}
async function test(){
let res = await ff()
}
test()
Promise 异常穿透与错误处理
// catch 等价于 =>
Promise.prototype.then(undefined, onRejected)
.then 对比 .catch
promise.then(f1).catch(f2);
promise.then(f1, f2);
两者不相等,不同之处在于,如果 f1 中出现 error,那么在第一个链式调用中,error 会被 catch 捕获,并在 f2 中被处理,但是在第二种写法中不会,这是因为 error 是沿着链传递的,而在第二段代码中,f1 和 f2处于同一层级,二者只会执行其一,下面没有链,所以 error 不会被处理。
new Promise((resolve, reject) => {
reject('失败了')
})
.then(
(data) => { console.log('onResolved1', data); },
(error) => { console.log('onRejected2', error); }
)
.catch(
(error) => {
console.log('catch', error)
}
)
"失败了"
就会被离它最近的 then 中的 onRejected
函数所处理,而不会被 catch 所捕获。
异步回调中的错误无法捕获
定时器这种异步中的错误,promise 捕获不到的
new Promise((resolve, reject) => {
setTimeout(() => {
throw new Error("Whoops!");
}, 1000);
})
.catch(error => {
console.log('catch error:', error);
});
executor 中的异步错误解决方案
在 executor 执行器中,不管最终拿到什么结果,建议都使用 resolve
或 reject
去接收
// 直接使用 reject 接收 error
new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("Whoops!"))
}, 1000);
})
也可以先用 try...catch
捕获 throw 出的 error,然后用 reject
去接收。
new Promise((resolve, reject) => {
setTimeout(() => {
try {
throw new Error("Whoops!");
} catch(error) {
reject(error)
}
}, 1000);
})
中断promise
返回一个状态一直为 pending 的 promise
.catch((err) => {
console.log('onRejected', err);
// 中断promise链:
return new Promise(() => {})
})
Promise的作用是什么
Promise是一种用于异步编程的JavaScript对象,它可以解决回调地狱的问题并提供更好的代码可读性和可维护性。
- 处理异步操作:在JavaScript中,异步操作比如Ajax请求、定时器等是很常见的,它们不能立即得到结果,而是需要等待一段时间才能得到结果。使用Promise可以方便地处理异步操作,避免阻塞UI线程,提高页面响应速度。
- 避免回调地狱:在传统的回调函数中,如果有多个异步操作需要执行,嵌套的回调会导致代码难以阅读和维护。而Promise通过链式调用的方式,可以避免这种嵌套的情况,使得代码更加清晰易懂。
- 提供更好的错误处理:Promise提供了catch方法来处理异常情况,使得代码更加健壮和可维护。在Promise中,任何一个操作的错误都可以在catch方法中捕获并进行处理,从而避免了在回调函数中抛出异常导致程序崩溃的情况。
- 便于组合操作:使用Promise可以方便地组合多个异步操作,使得代码更加简洁和可读性更强。例如,我们可以使用Promise.all方法来并行执行多个异步操作,并在所有操作完成后进行下一步处理。