异步编程的四种方式
回调函数
获取异步任务的结果。假设有两个函数f1和f2,f2需要等待f1的执行结果,如果f1是一个需要很长时间来执行的代码,则需要考虑改写f1,将f2作为f1的回调函数1
2
3
4
5
6
7
8function f1(callback){
setTimeout(function(){
// f1的任务代码
callback();
}, 1000)
}
f1(f2) // 执行代码会变成这样
采用回调函数的方式,将同步操作变成异步,f1不会阻塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行
它的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,流程会很混乱,而且每个任务只能指定一个回调函数。
事件监听
任务执行不取决于代码的顺序,而是事件是否发生(采用jQuery的写法)1
f1.on('done', f2); // 当f1发生done事件,就执行f2
再改写f1中的代码1
2
3
4
5
6function f1(){
setTimeout(function(){
// f1任务代码
f1.trigger('done') // 执行完成后,立即触发done事件,从而开始执行f2
}, 1000)
}
它的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以解耦,有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
发布订阅模式
又称为观察者模式,将上面的事件理解成信号,假设有个信号中心,某个任务执行完就向中心发布一个信号,其他依赖于这个任务的可以向信号中心订阅这个信号,从而知道什么时间自己开始执行1
jQuery.subscribe("done", f2); // f2向信号中心jQuery订阅done信号
接着对f1进行改写1
2
3
4
5
6function f1(){
setTimeout(function(){
// f1的任务代码
jQuery.publish("done"); // f1执行完后,向信号中心发送done信号,从而触发f2执行
}, 1000);
}
与事件监听性质十分类似,但优于前者,我们可以通过信号中心查看设置了多少个信号,以及每个信号有多少个订阅者,从而监控程序运行
Promise对象
定义:(参考阮一峰教程)
Promise 是一个对象,对象里存储一个状态,这个状态是可以随着内部的执行转化的,为以下三种状态之一:等待态(Pending)、完成态(Fulfilled)、拒绝态(Rejected)。
一开始,我们先设置好等状态从 pending 变成 fulfilled 和 rejected 的预案(当成功后我们做什么,失败时我们做什么)。
Promise 启动之后,当满足成功的条件时我们让状态从 pending 变成 fulfilled (执行 resolve);当满足失败的条件,我们让状态从 pending 变成 rejected(执行 reject)
promise是回调的一种形式,同时也是一个事务管理器。他的作用是将各种内嵌回调的事务用流水形式表达,其目的是为了简化编程,让代码逻辑更加清晰。
1、then的链式用法(结合jQuery的写法)
1 | $.ajax({ |
2、自己生成一个Promise对象
1 | function returnPromise(){ |
3、async和await(两者的关系是相互依赖,通过await模拟同步代码)
1 | function returnPromise(){ |
4、try…catch
捕获报错信息,catch是一个没有成功函数的失败函数,可以想象成then的语法糖1
2
3
4
5
6
7
8
9
10function returnPromise(){
... ...
}
try{
var promise = await xxx()
console.log('没出错')
}catch(error){
console.log('异常了')
}