回调函数:最基础的异步处理
在早期的网络编程中,回调函数是最常见的异步调用方式。比如你发一个HTTP请求,不想卡住主线程,就传一个函数进去,等数据回来自动执行。
像Node.js里的fs.readFile就是典型例子:
fs.readFile('./data.txt', function(err, data) {
if (err) throw err;
console.log(data.toString());
});
这种方式简单直接,但嵌套多了容易“回调地狱”,代码层层缩进,读起来费劲。
Promise:让异步更清晰
为了解决回调嵌套问题,Promise出现了。它把异步操作变成链式调用,逻辑更线性。
比如用fetch发起网络请求:
fetch('/api/user/1')
.then(response => response.json())
.then(user => console.log(user))
.catch(error => console.error(error));
每个.then处理上一步的结果,出错统一.catch,结构清楚了不少。
async/await:像写同步一样写异步
真正让异步代码变得“顺眼”的是async/await。它基于Promise,但写法更自然。
还是上面的例子:
async function getUser() {
try {
const response = await fetch('/api/user/1');
const user = await response.json();
console.log(user);
} catch (error) {
console.error(error);
}
}
看起来就像同步代码,但不会阻塞主线程。现在大多数现代前端和Node.js项目都这么写。
事件驱动:适用于高并发场景
在服务端网络编程中,比如用Node.js写Web服务器,事件驱动模型很常见。请求来了触发事件,处理完再发出响应。
比如原生HTTP模块:
const http = require('http');
const server = http.createServer();
server.on('request', (req, res) => {
res.end('Hello World');
});
server.listen(3000);
这种模式适合处理大量并发连接,像聊天服务器、实时推送这类应用。
使用消息队列解耦异步任务
在复杂系统中,有些网络请求不需要立刻完成,比如发邮件、处理图片。这时候可以把任务丢到消息队列里,由后台进程慢慢处理。
比如用户注册后发欢迎邮件:
// 注册逻辑
saveUser(userData);
// 异步发邮件,不等结果
messageQueue.send('send_welcome_email', userData.email);
用RabbitMQ、Kafka这类工具,既能保证最终执行,又不会拖慢主流程。
浏览器中的Web Workers
虽然主要用在计算密集型任务,但Web Workers也能间接支持异步网络调用。把耗时请求放到Worker里,避免页面卡顿。
// main.js
const worker = new Worker('worker.js');
worker.postMessage('/api/large-data');
worker.onmessage = function(e) {
console.log('收到数据:', e.data);
};
// worker.js
self.onmessage = function(e) {
fetch(e.data)
.then(r => r.json())
.then(data => self.postMessage(data));
};
适合处理大数据量接口,不影响用户操作。