1. 回调函数
// 异步请求
ajax(url, () => {
// 请求返回后的逻辑处理
})
// 读取文件
fs.readFile('/etc/shells', function (err, data) {
// 文件读取完毕后的操作
console.log(data);
});
优点:简单、容易理解和部署
缺点:回调地狱,不利于代码的阅读和维护,各个部分之间高度耦合,流程会很混乱,而且每个任务只能指定一个回调函数
2. 事件监听
采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
假设两个函数f1和f2,要求f2必须等到f1执行完成后才能执行。
f1.on('done', f2);
function f1() {
setTimeout(function () {
// ...
f1.trigger('done');
}, 1000);
}
f1.trigger(‘done’)表示,执行完成后,立即触发done事件,从而开始执行f2。
优点 :可以绑定多个事件,每个事件可以指定多个回调函数,而且可以去耦合,有利于实现模块化
缺点:是整个程序都要变成事件驱动型,运行流程会变得很不清晰
3. 发布/订阅
发布/订阅模式,又称观察者模式。
假设存在一个“信号中心”,某个任务执行完成,就向信号中心“发布”(publish)一个信号,其他任务可以向信号中心“订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行
//f2向Jquery订阅done信号
jQuery.subscribe("done", f2);
function f1() {
setTimeout(function () {
// f1的逻辑处理
// 发布done信号
jQuery.publish("done");
}, 1000);
}
//f2执行完成后,取消订阅
jQuery.unsubscribe("done", f2);
优点:性质与“事件监听类似”,但是明显优于后者,因为我们可以通过查看”消息中心“,了解存在多少信号,多少个订阅者,从而监听程序的运行。
4. Promises
Promise就是为了解决回调地狱而产生的,将回调函数的嵌套,改成链式调用。
简单说,它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。
// a.md内容为 "b"
// b.md内容为 "c"
var readFile = require('fs-readfile-promise');
readFile("a.md")
.then(function (data) {
console.log(data.toString());
return readFile(data.toString() + ".md");
})
.then(function (data) {
console.log(data.toString());
})
.catch(function (err) {
console.log(err);
});
// b
// c
优点:解决回调地狱,链式调用,使用then方法以后,异步任务的两段执行逻辑更清晰
缺点:代码冗余,一堆 then使得原来的语义变得不清晰
5. 生成器函数 Generator / yield
Generator 函数是 ES6 提供的一种异步编程解决方案。
yield表达式可以暂停函数执行,next方法用于恢复函数执行,这使得Generator函数非常适合将异步任务同步化。
yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。
每个yield返回的是{value:yield返回的值,done:true/false(执行状态)}
function* genFun() {
yield 'hello';
yield 1 + 1;
return 'world';
}
let demo = genFun()
demo.next() // { value: 'hello', done: false }
demo.next() // { value: 2, done: false }
demo.next() // { value: 'world', done: ture }
demo.next() // { value: undefined, done: ture }
优点:解决回调地狱,异步操作表示得很简洁
缺点:流程管理不方便,即何时执行第一阶段,何时执行第二阶段,如何实现自动化的流程管理。
6. async / await 函数的实现
async 是“异步”的意思,await 是等待的意思。
async 用于申明一个 异步的 function(实际上是async function 对象)
await 用于等待一个异步任务执行完成的的结果。并且 await 只能出现在 async 函数中。
async 函数返回的是一个 Promise 对象,可以使用 then 方法添加回调函数,async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数。当函数执行的时候,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。(await 命令后面返回的是 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在try…catch代码块中。)
async function f1() {
let newTime = await new Promise((resolve, reject) => {// 等待异步返回结果,再继续向下执行
let time = 3000;
setTimeout(() => {
resolve(time);
}, time)
})
console.log(newTime + '毫秒后执行');
let content = 'test';
console.log(content);
}
f1() // 3s后,先输出 “3000毫秒后执行”,再输出 "test"
优点:异步编程终极解决方案,化异步为同步
缺点:暂无
本文探讨了多种JavaScript异步编程方法,包括回调函数、事件监听、发布/订阅模式、Promise、生成器和async/await。它们各自有优缺点,如回调函数可能导致回调地狱,而async/await提供了更清晰的异步流程控制。文章旨在展示如何逐步改进异步代码的可读性和维护性。
2736

被折叠的 条评论
为什么被折叠?



