Quod tempora sit beatae et vitae sed reprehenderit fuga. Aut corrupti nihil error libero veniam. Fuga quo ut ipsa delectus tenetur occaecati aut. Impedit itaque fuga necessitatibus.
在 JavaScript 中,同步(Synchronous) 和 异步(Asynchronous) 是两种不同的执行方式,它们主要影响代码执行的顺序和程序的响应性。
同步执行意味着任务会按照它们在代码中的顺序逐个执行。每个任务必须等前一个任务完成后才能继续执行,这会导致程序在执行某个任务时阻塞,直到该任务完成。
console.log('Start');
function task1() {
console.log('Task 1 started');
for (let i = 0; i < 1e8; i++) {} // 模拟一个耗时操作
console.log('Task 1 completed');
}
function task2() {
console.log('Task 2 started');
for (let i = 0; i < 1e8; i++) {} // 模拟一个耗时操作
console.log('Task 2 completed');
}
task1();
task2(); // task2 会等 task1 完成后再执行
console.log('End');
输出:
Start
Task 1 started
Task 1 completed
Task 2 started
Task 2 completed
End
在这个例子中,task1
执行完成后,task2
才会开始执行,代码是逐行顺序执行的,task2
要等 task1
完成后才会开始执行。
异步执行指的是,任务在发起时不会等待其他任务完成,而是继续执行后续代码,任务在后台执行,等到执行完毕后,通过回调函数、Promise
或 async/await
机制来处理结果。
Promise
/async/await
等机制来处理。console.log('Start');
function task1(callback) {
console.log('Task 1 started');
setTimeout(function() { // 模拟异步操作
console.log('Task 1 completed');
callback(); // 执行回调,通知任务完成
}, 1000);
}
function task2() {
console.log('Task 2 started');
// 模拟同步操作
console.log('Task 2 completed');
}
task1(function() {
task2(); // task2 会在 task1 完成后执行
});
console.log('End');
输出:
Start
Task 1 started
End
Task 1 completed
Task 2 started
Task 2 completed
在这个例子中,task1
通过 setTimeout
来模拟一个异步任务,在 task1
执行时,程序不会等待它完成,而是会继续执行 console.log('End')
。当 task1
完成后,回调函数会执行 task2
。
JavaScript 是单线程的,意味着它一次只能做一件事。为了处理 I/O 密集型操作(如网络请求、文件读写等),JavaScript 使用 事件循环(Event Loop) 机制来异步执行代码。
setTimeout
, 网络请求的回调等)会被推送到任务队列中,等待主线程空闲时执行。console.log('Start');
setTimeout(function() {
console.log('Inside setTimeout');
}, 0);
console.log('End');
输出:
Start
End
Inside setTimeout
在这个例子中,虽然 setTimeout
设置了 0 毫秒的延迟,JavaScript 仍然会先执行同步代码(console.log('Start')
和 console.log('End')
)。setTimeout
的回调会被推到任务队列中,等待调用栈为空时执行,所以 Inside setTimeout
会在同步代码执行完后才打印出来。
回调函数是最基本的异步处理方式,它是一个函数,作为参数传递给另一个函数,等异步操作完成时调用。
function fetchData(callback) {
setTimeout(function() {
console.log('Data fetched');
callback();
}, 1000);
}
fetchData(function() {
console.log('Callback executed');
});
Promise
是异步编程的一种改进,它代表一个可能完成或失败的异步操作,并允许你在未来的某个时刻处理其结果。Promise
使得异步代码更加可读,并且避免了“回调地狱”(callback hell)。
let fetchData = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('Data fetched');
resolve('Data');
}, 1000);
});
fetchData.then((data) => {
console.log('Received:', data);
}).catch((error) => {
console.log('Error:', error);
});
async/await
是基于 Promise
的语法糖,使得异步代码看起来像是同步的,从而提高了可读性。async
修饰函数,await
用于等待 Promise
的结果。
async function fetchData() {
console.log('Fetching data...');
let data = await new Promise(resolve => {
setTimeout(() => resolve('Data fetched'), 1000);
});
console.log(data);
}
fetchData();
特性同步 (Synchronous)异步 (Asynchronous)
执行顺序按顺序执行,当前任务完成后才会执行下一个任务不按顺序执行,当前任务不会阻塞,后续任务可以立即执行
阻塞阻塞,当前任务完成前不能执行后续任务非阻塞,任务会在后台执行,执行完后通过回调、Promise 或 await 处理结果
性能对于 I/O 密集型操作,性能差,容易阻塞线程高效,适用于处理大量 I/O 操作,不会阻塞主线程
使用场景当任务之间有顺序依赖关系时,适合使用同步当需要同时处理多个任务时,适合使用异步,尤其是 I/O 操作(例如网络请求)
Promise
、async/await
等方式实现,并通过事件循环机制确保异步任务的执行顺序。异步编程在 JavaScript 中非常重要,尤其是在 Web 开发中,处理异步请求(如 HTTP 请求)和其他 I/O 操作时,异步编程能够显著提高性能和响应速度。