一、JavaScript异步编程方式
JavaScript异步编程方式有回调函数、promise、Generator、async。
(一)回调函数
当使用回调函数进行异步编程时,可能会出现代码嵌套过深的情况,导致代码变得难以理解和维护。同时,由于多个回调函数的嵌套,使得代码的耦合度过高,不利于代码的模块化和复用。
function asyncFunc1(callback) {
setTimeout(() => {
console.log("异步操作1完成");
callback();
}, 1000);
}
function asyncFunc2() {
console.log("异步操作2开始");
asyncFunc1(() => {
console.log("回调函数嵌套");
});
console.log("异步操作2结束");
}
asyncFunc2();
(二)Promise
Promise 提供了一种链式调用的方式来解决回调函数地狱的问题,但在多个 Promise 串联的情况下,可能会导致代码的语义不够清晰。
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Promise异步操作完成");
resolve();
}, 1000);
});
promise
.then(() => {
console.log("Promise then 调用");
})
.catch((err) => {
console.log("Promise catch 调用");
});
(三)Generator
Generator 允许在函数的执行过程中暂时将执行权转移给其他函数或异步操作,然后在执行完成后自动恢复执行。这种机制可以让我们以同步的方式编写异步逻辑,但需要解决何时恢复执行权的问题,通常需要借助自动执行 Generator 的机制来实现。
function* generatorFunc() {
yield new Promise((resolve) => {
setTimeout(() => {
console.log("Generator异步操作完成");
resolve();
}, 1000);
});
}
let generator = generatorFunc();
let res = generator.next(); // 开始执行生成器函数,遇到yield语句,暂停执行,返回一个对象{value: ..., done: ...}
while (!res.done) {
// 如果done属性为false,继续执行生成器函数,直到遇到下一个yield语句,然后暂停,返回一个对象{value: ..., done: ...}。如果done属性为true,说明生成器函数已经执行完毕。
res = generator.next();
}
(四)Async
Async 函数是一种更简洁、自动执行的语法糖,它基于 Promise 实现,通过 await 关键字等待异步操作的完成。Async 函数允许我们将异步逻辑转化为同步的顺序,并提供自动执行的能力,简化了异步编程的流程。
async function asyncFunc() {
console.log("Async 函数开始");
await new Promise((resolve, reject) => {
// 遇到await语句,暂停执行,返回一个Promise对象。当Promise对象的状态变为resolve后,继续执行async函数。如果Promise对象的状态变为reject,抛出异常。
setTimeout(() => {
console.log("Async 异步操作完成");
resolve();
}, 1000);
});
console.log("Async 函数结束"); // 在这里,由于前面有await语句,所以这个语句会在异步操作完成后执行。
}
asyncFunc(); // 自动执行async函数。如果async函数内部有await语句,那么这个函数会等待所有的await语句都执行完成后,再继续执行。
二、JavaScript异步编程的优劣
(一)优势
- 提高性能:异步编程可以避免线程阻塞,提高程序的执行效率。在处理大量计算或IO操作时,不会消耗过多的系统资源,从而提高程序的性能。
- 更好的用户体验:异步编程可以减少用户界面的延迟,提高应用程序的响应速度。当程序需要执行一些耗时的任务时,不会阻止用户界面的响应用户的操作,从而提供更好的用户体验。
- 更好的服务器端应用:异步编程可以更好地处理高并发请求,提高服务器的处理能力。由于异步请求不会阻塞服务器,因此可以同时处理更多的请求,适用于大规模的服务器端应用。
(二)劣势
- 代码复杂度增加:异步编程需要使用回调函数、Promise等异步编程模式,使得代码变得更加复杂,可读性和可维护性降低。
- 错误处理难度增加:异步编程中,错误可能发生在不同的时间点,需要使用特定的方式来捕获和处理错误,增加了错误处理的难度。
- 资源占用较多:由于异步编程需要创建多个线程或进程来同时执行任务,因此需要更多的系统资源,如内存、CPU等。在资源有限的情况下,可能会影响程序的性能。