🖼️ Lyin's Room

Search

Search IconIcon to open search

异步操作

Last updated Unknown

# 异步操作的模式

# 回调函数

回调函数是异步操作最基本的方法。

下面是两个函数f1f2,编程的意图是f2必须等到f1执行完成,才能执行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function f1() {
  // ...
}

function f2() {
  // ...
}

f1();
f2();

上面代码的问题在于,如果f1是异步操作,f2会立即执行,不会等到f1结束再执行。

这时,可以考虑改写f1,把f2写成f1的回调函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function f1(callback) {
  // ...
  callback();
}

function f2() {
  // ...
}

f1(f2);

回调函数的优点是简单、容易理解和实现,缺点是不利于代码的阅读和维护,各个部分之间高度 耦合(coupling),使得程序结构混乱、流程难以追踪(尤其是多个回调函数嵌套的情况),而且每个任务只能指定一个回调函数。

# 事件监听

另一种思路是采用事件驱动模式。异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

还是以f1f2为例。首先,为f1绑定一个事件(这里采用的 jQuery 的 写法)。

1
f1.on('done', f2);

上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写:

1
2
3
4
5
6
function f1() {
  setTimeout(function () {
    // ...
    f1.trigger('done');
  }, 1000);
}

上面代码中,f1.trigger('done')表示,执行完成后,立即触发done事件,从而开始执行f2

这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以“ 去耦合”(decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。阅读代码的时候,很难看出主流程。

# promise

异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理且更强大。

有三个状态:

  1. pending 待定 初始状态
  2. fulfilled 实现 操作成功
  3. rejected 拒绝 操作失败
1
2
3
4
5
6
7
8
var promise = new Promise(传一个函数);
var promise = new Promise(function (resolve, reject) {
	if (/*异步操作成功*/) {
	resolve(value)
	} else {
	reject(error);
	}
})

当promise状态发生改变就会触发then()里的响应函数处理后续步骤。(promise.then(函数)

状态改变只有两种可能

  1. 从pending变为fulfilled
  2. 从pending变为rejected