JS异步编程方法的6种方案总结
异步编程和JS单线程模型
在JavaScript中,任务队列是基于事件循环(event loop)实现的,主线程执行完同步任务后,会被阻塞,直到下一个异步任务添加到任务队列中。当所有的同步任务都执行完毕后,主线程会去任务队列中取出第一个任务并执行。
这种机制就决定了JavaScript是单线程的,因为当主线程被阻塞时,不能同时处理其他任务。
异步编程的目的就是在不阻塞主线程的情况下,执行一些大量耗时或者需要等待某些外部事件才能完成的操作。
6种异步编程方案
- 回调函数(callback)
- Promise
- async/await
- 事件监听(EventEmitter)
- 发布订阅(Publish/Subscribe)
- generator/yield
1. 回调函数(callback)
回调函数是最早的异步编程方法,将异步任务封装成函数,当任务完成后将结果传递给回调函数并执行。这种方法在性能上比较好,但是嵌套回调会造成代码可读性和维护性的问题。
例如:
function readFile(callback) {
// 读取文件
const fileContent = "This is file content."
callback(fileContent)
}
readFile(function(content) {
console.log(content)
})
2. Promise
Promise是ES6新增的异步编程机制,本质上是一个状态机。通过链式调用then和catch方法来处理异步操作的完成和错误。
例如:
function readFile() {
return new Promise((resolve, reject) => {
// 读取文件
const fileContent = "This is file content."
resolve(fileContent)
})
}
readFile().then((content) => {
console.log(content)
}).catch((error) => {
console.error(error)
})
3. async/await
async/await是ES2017中新增的异步编程方式,是Promise的语法糖。async用于修饰函数,声明该函数是异步的;await用于等待异步操作完成,并获取操作的返回结果。
例如:
async function readFile() {
// 读取文件
const fileContent = "This is file content."
return fileContent
}
(async function() {
const content = await readFile()
console.log(content)
})()
4. 事件监听(EventEmitter)
事件监听是Node.js中比较常见的异步编程方式,主要通过发布/订阅模式实现。使用events模块中的EventEmitter类创建一个监听器对象,调用on方法监听特定类型的事件,并在触发该事件后执行注册的回调函数。
例如:
const EventEmitter = require('events')
const myEmitter = new EventEmitter()
myEmitter.on('readFile', (content) => {
console.log(content)
})
function readFile() {
// 读取文件
const fileContent = "This is file content."
myEmitter.emit('readFile', fileContent)
}
readFile()
5. 发布订阅(Publish/Subscribe)
发布订阅是一种更加灵活的异步编程方式,通过在发布者和订阅者之间加入一个调度中心来实现。发布者向调度中心发布消息,订阅者从调度中心订阅消息,并在消息到达时执行相应的操作。
例如:
class Event {
constructor() {
this.handlers = {}
}
addEventHandler(name, handler) {
if (!this.handlers[name]) {
this.handlers[name] = []
}
this.handlers[name].push(handler)
}
removeEventHandler(name, handler) {
const index = this.handlers[name].indexOf(handler)
if (index != -1) {
this.handlers[name].splice(index, 1)
}
}
fireEvent(name, ...args) {
if (this.handlers[name]) {
this.handlers[name].forEach(handler => {
handler.apply(this, args)
})
}
}
}
const event = new Event()
event.addEventHandler('readFile', (content) => {
console.log(content)
})
function readFile() {
// 读取文件
const fileContent = "This is file content."
event.fireEvent('readFile', fileContent)
}
readFile()
6. generator/yield
generator/yield也是ES6新增的异步编程方式,可以将异步编程看成是迭代器。调用生成器函数返回一个迭代器,再调用迭代器的next方法可以执行异步操作,yield表达式可以将异步操作和处理返回结果的操作分别定义在不同的位置。
例如:
function* readFile() {
// 读取文件
const fileContent = "This is file content."
const result = yield fileContent
console.log(result)
}
const generator = readFile()
readingFile().next().value.then((content) => {
readingFile().next("Result").value
})
总结
异步编程对于JavaScript语言来说至关重要。六种不同的异步编程方式各有优缺点,需要根据具体的场景来选择合适的方式实现异步操作。同时,异步编程也需要在保证功能的前提下,去考虑代码的可读性和维护性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS异步编程方法的6种方案总结 - Python技术站