异步编程#
约 411 个字 5 行代码 预计阅读时间 8 分钟
使用回调的异步编程#
延时任务#
setTimeout
用于在指定的时间后执行一次函数。它接受两个参数:要执行的函数和延迟的时间(以毫秒为单位)。
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>延时任务</title>
</head>
<body>
<div id="root"></div>
<!--封装print方法,用于页面信息输出-->
<script src="../js/print.js"></script>
<script>
print("准备执行异步方法")
/*
* 会在1秒后调用回调函数
* */
setTimeout(callBack, 1000)
print("主程序会继续执行,并不会等待延时任务执行完再执行")
/*
* 回调函数
* */
function callBack() {
print("1秒后,回调执行")
}
</script>
</body>
</html>
定时任务#
setInterval
用于在指定的时间间隔内重复执行一次函数。它接受两个参数:要执行的函数和间隔时间(以毫秒为单位)。
可以使用clearInterval
来停止定时任务。
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>定时任务</title>
</head>
<body>
<div id="root"></div>
<!--封装print方法,用于页面信息输出-->
<script src="../js/print.js"></script>
<script>
print("准备执行异步方法")
/*
* 每隔一秒执行一次回调
* */
const interval = setInterval(callBack, 1000);
print("主程序会继续执行,会不会等待定时任务执行完再执行")
let i = 0;
function callBack() {
print("1秒后,回调执行")
if (++i === 5) {
clearInterval(interval)
}
}
</script>
</body>
</html>
事件#
通过addEventListener
来注册回调函数,当指定事件发时会调用这些函数。
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件</title>
</head>
<body>
<button id="btn">点击</button>
<script>
const btn = document.getElementById('btn');
// 通过addEventListener注册回调函数
btn.addEventListener('click', buttonClick);
// 回调函数
function buttonClick() {
alert("按钮被点击了")
}
</script>
</body>
</html>
网络请求#
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>网络请求</title>
</head>
<body>
<div id="root"></div>
<!--封装print方法,用于页面信息输出-->
<script src="../js/print.js"></script>
<script>
print("准备发送网络请求")
const request = new XMLHttpRequest();
request.open("GET", "https://httpbin.org/");
request.send();
// 注册响应到达的回调函数
request.onload = function () {
print("收到响应,响应码为:" + request.status)
}
// 注册网络出错的回调
request.onerror = function (e) {
print("网络错误:" + e.type)
}
print("主程序会继续执行,不会等待网络请求收到响应后再执行。")
</script>
</body>
</html>
期约(Promise)#
回调地狱问题#
- 基于
回调
的异步编程会出现回调多层嵌套
的情况,导致代码缩进过多难以阅读。 - 回调函数中发生异常,异步的发起者无法获取和处理异常。
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>回调地狱</title>
</head>
<body>
<div id="root"></div>
<!--封装print方法,用于页面信息输出-->
<script src="../js/print.js"></script>
<script>
setTimeout(() => {
print("执行第一次回调");
setTimeout(() => {
print("第一次回调结束,执行第二次回调")
setTimeout(() => {
print("第二次回调结束,执行第三次回调")
setTimeout(() => {
print("第三次回调结束,执行第四次回调")
setTimeout(() => {
print("第四次回调结束,执行第五次回调")
throw new Error("发生异常")
}, 1000)
}, 1000)
}, 1000)
}, 1000)
}, 1000)
</script>
</body>
</html>
期约概述#
期约(Promise)
是为了简化异步编程。
期约是一个对象,表示异步操作的结果。
相比于回调处理异步操作,期约做出如下改进:
- 期约可以让回调地狱以一种更线性的
期约链
形式表达出来。 - 期约标准化了异常处理,通过期约链提供了一种让错误正确传播的途径。
Warning
不能使用期约替代setInterval
。期约不能表示重复的异步计算,这并不是期约所考虑的用例。
也不应该使用期约替代事件,事件往往可以重复触发,不需要等待上一条事件执行完毕。
示例#
期约链#
期约链更容易表达一连串异步操作。