JavaScript异步编程的四种方法包括回调函数、事件监听、Promise和async/await。
1. 回调函数
回调函数。这是异步编程最基本的方法,适用于处理异步任务。例如,如果有一个耗时的任务f1,可以将其作为回调函数,将另一个函数f2作为参数传入。f1执行完成后,会执行f2,这样就不会堵塞程序的运行,而是先执行主要逻辑,将耗时的操作推迟执行。回调函数的优点是简单、容易理解和部署,但缺点是不利于代码的阅读和维护,因为各个部分之间高度耦合,流程可能会变得混乱,且每个任务只能指定一个回调函数。
假定有两个函数f1和f2,后者等待前者的执行结果。
f1();
f2();
如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。
function f1(callback){
setTimeout(function () {
// f1的任务代码
callback();
}, 1000);
}
执行代码就变成下面这样:f1(f2);
采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。
回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,流程会很混乱,而且每个任务只能指定一个回调函数。
2.事件监听
另一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。还是以f1和f2为例。首先,为f1绑定一个事件。(这里采用的jQuery的写法)。
f1.on('done', f2);
上面这行代码的意思是,当f1发生done事件,就执行f2。然后,对f1进行改写:
function f1(){
setTimeout(function () {
// f1的任务代码
f1.trigger('done');
}, 1000);
}
f1.trigger('done')表示,执行完成后,立即触发done事件,从而开始执行f2。
这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。
3. Promises对象
Promise 是ES6新规范,Promise 是js 中异步编程新解决方案。以下简称 Promise为P,
从语法上来说P是一个构造函数,从功能上来说,P 对象用来封装一个异步并获取其成功/失败的结果值。
P 支持链式调用,可以解决回调地狱的问题。回调地狱指的是一个回调函数嵌套着另一个异步任务,不便于阅读,不便于异常处理,
P 的流程是启动异步任务=》返回Promise 对象 =》给promise 对象绑定回调函数。
// 创建一个返回Promise对象的函数
function asyncFunction() {
return new Promise((resolve, reject) => {
// 模拟异步操作
setTimeout(() => {
const data = '这是从服务器获取到的数据';
if (data) {
resolve(data); // 成功时调用resolve并传递结果
} else {
reject('无法获取数据'); // 失败时调用reject并传递错误信息
}
}, 2000);
});
}
// 调用asyncFunction函数并处理其返回的Promise对象
asyncFunction().then((result) => {
console.log(`成功获取到数据:${result}`);
}).catch((error) => {
console.error(`发生了错误:${error}`);
});
在上面的代码中,我们定义了一个名为asyncFunction
的函数,该函数返回一个Promise对象。通过将需要进行异步操作的任务放入setTimeout函数内部,我们模拟了一个延迟两秒后才能得到数据的情景。当异步操作完成后,如果有数据则调用resolve
方法并传递结果;否则,调用reject
方法并传递错误信息。最后,我们通过.then()
方法来处理Promise对象的成功状态,并通过.catch()
方法来处理Promise对象的失败状态。
4. async/await 函数的实现
async/await这是ES2017引入的异步编程语法。
JavaScript中的async/await
可以用于处理异步操作。下面是使用JavaScript实现async/await
异步编程的示例代码:
// 定义一个返回Promise对象的函数
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// 使用async关键字标记该函数为异步函数
async function asyncFunction() {
// await关键字等待delay函数完成并获取其结果
const result = await delay(2000);
console.log('Delayed for 2 seconds');
console.log(`Result: ${result}`);
}
// 调用异步函数
asyncFunction();
在上述代码中,我们首先定义了一个名为delay
的函数,它接收一个参数表示延时的毫秒数,然后返回一个包装了setTimeout的Promise对象。这样就能模拟一些需要花费时间才能得到结果的异步操作。
接下来,我们通过将async
关键字添加到函数前面,将其转换为一个异步函数。在异步函数内部,我们使用await
关键字等待delay
函数完成并获取其结果。当await
语句被执行时,异步函数会立即暂停执行,直到delay
函数返回结果或者超时。
最后,我们调用asyncFunction()
来开始整个流程。输出结果应该是"Delayed for 2 seconds"和"Result: undefined"(因为delay
函数没有返回任何值)。