# JavaScript教程 - 19 异步编程
# 19.1 异步和同步
什么是同步和异步?
同步就是代码一行一行执行,前一行不执行完,后一行不会执行。
但有时候某些操作(如网络请求、文件读取、定时器等)可能很慢,这时候如果继续同步执行,会“阻塞”后续代码执行,影响用户体验。
异步编程的出现就是为了解决这个问题:让程序能在等待某些操作完成的同时,继续做别的事。
举个栗子:
同步代码:
console.log('1');
console.log('2');
console.log('3');
// 输出顺序就是 1 -> 2 -> 3
1
2
3
4
5
2
3
4
5
- 上面的代码,一行一行按照顺序执行。
异步代码:
console.log('1');
setTimeout(() => {
console.log('2');
}, 1000);
console.log('3');
// 实际输出顺序是:1 -> 3 -> (等待1秒)-> 2
1
2
3
4
5
6
7
2
3
4
5
6
7
setTimeout
是一种异步方法,它不会阻塞主线程。
# 19.2 回调地狱
异步最常见的方式就是回调函数,举个栗子:
function doSomethingAsync(callback) {
setTimeout(() => {
console.log('执行任务...');
callback(); // 任务完成后再执行回调
}, 1000);
}
doSomethingAsync(() => {
console.log('回调被调用');
});
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 在上面的代码中,当任务执行完成后,会调用回调函数。
回调函数简单的还好,但是如果嵌套过多,会导致 回调地狱。
举个栗子:
我们模拟三个任务,每个任务耗时 1 秒,并且后一个任务需要用到前一个任务的结果:
function task1(callback) {
setTimeout(() => {
console.log("任务1");
callback("结果1");
}, 1000);
}
function task2(input, callback) {
setTimeout(() => {
console.log("任务2,接收到任务1的数据:", input);
callback("结果2");
}, 1000);
}
function task3(input, callback) {
setTimeout(() => {
console.log("任务3,接收到任务2的数据:", input);
callback("结果3");
}, 1000);
}
// 回调地狱开始:
task1(function (result1) {
// 任务1的结构result1传递给任务2
task2(result1, function (result2) {
// 任务2的结构result2传递给任务3
task3(result2, function (result3) {
console.log("所有任务完成,最终结果:", result3);
});
});
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- 虽然上面的任务是一个一个执行,逻辑是线性的,但代码却层层嵌套;所有逻辑耦合在一起,而且嵌套太深,看不清逻辑结构,这就是回调地狱。
那么如何解决回调地狱问题呢?
# 19.3 Promise
Promise 是 ES6 引入的一个构造函数,用于表示一个可能当前没值、但将来可能会返回值的对象,它用于管理异步操作的执行和结果,可以用来优化回调地狱。
内容未完......