# JavaScript教程 - 19 异步编程

# 19.1 异步和同步

什么是同步和异步?

同步就是代码一行一行执行,前一行不执行完,后一行不会执行。

但有时候某些操作(如网络请求、文件读取、定时器等)可能很慢,这时候如果继续同步执行,会“阻塞”后续代码执行,影响用户体验。

异步编程的出现就是为了解决这个问题:让程序能在等待某些操作完成的同时,继续做别的事。

举个栗子:

同步代码:

console.log('1');
console.log('2');
console.log('3');

// 输出顺序就是 1 -> 2 -> 3
1
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
  • setTimeout 是一种异步方法,它不会阻塞主线程。

# 19.2 回调地狱

异步最常见的方式就是回调函数,举个栗子:

function doSomethingAsync(callback) {
  setTimeout(() => {
    console.log('执行任务...');
    callback(); // 任务完成后再执行回调
  }, 1000);
}

doSomethingAsync(() => {
  console.log('回调被调用');
});
1
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
  • 虽然上面的任务是一个一个执行,逻辑是线性的,但代码却层层嵌套;所有逻辑耦合在一起,而且嵌套太深,看不清逻辑结构,这就是回调地狱。

那么如何解决回调地狱问题呢?

# 19.3 Promise

Promise 是 ES6 引入的一个构造函数,用于表示一个可能当前没值、但将来可能会返回值的对象,它用于管理异步操作的执行和结果,可以用来优化回调地狱。

内容未完......