前言
JavaScript是一种单线程语言,这意味着它一次只能执行一个任务。这种设计简化了编程模型,但也带来了挑战:如何处理耗时操作而不阻塞主线程?
一、 异步编程基础
1.同步 vs 异步执行
arduino
// 同步代码示例
console.log(1);
console.log(2);
console.log(3);
// 输出顺序:1 2 3
2.异步代码示例
javascript
console.log(1);
setTimeout(function() {
console.log(2);
}, 1000);
console.log(3);
// 输出顺序:1 3 2(1秒后)
其中setTimeout是一个延迟函数,设定在一秒后执行,所以改变了原有的代码执行顺序
3.事件循环机制
JavaScript通过事件循环机制处理异步操作:
- 同步代码立即执行
- 异步代码被放入事件队列
- 当调用栈为空时,事件队列中的任务按顺序执行
二、Promise:异步编程的解决方案
1.Promise基本用法
javascript
const promise = new Promise((resolve, reject) => {
// 异步操作代码
// 成功时调用 resolve(value)
// 失败时调用 reject(error)
});
2. 示例
javascript
console.log(1);
const p = new Promise((resolve) => {
setTimeout(function() {
console.log(2);
resolve();
}, 3000);
});
p.then(() => {
console.log(3);
});
console.log(4);
// 输出顺序:1 4 2 3
3.Promise处理文件读取
javascript
import fs from 'fs';
console.log(1);
const p = new Promise((resolve, reject) => {
console.log(3); // 同步执行
fs.readFile('./a.txt', function(err, data) {
if (err) {
reject(err);
return;
}
resolve(data.toString());
});
});
p.then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
console.log(4);
// 输出顺序:1 3 4 [文件内容]
注意:被Promise实例包裹的同步代码并不会延时触发,而是正常按照顺序执行
三、fetch API:网络请求
javascript
// 基本用法
fetch("https://api.github.com/orgs/lemoncode/members")
.then((response) => response.json())
.then((data) => {
// 处理数据
console.log(data);
})
.catch((error) => {
console.error('Error:', error);
});
实际应用示例
xml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>GitHub Members</title>
</head>
<body>
<ul id="members"></ul>
<script>
fetch("https://api.github.com/orgs/lemoncode/members")
.then((response) => response.json())
.then((members) => {
const membersList = document.getElementById("members");
membersList.innerHTML = members
.map((member) => {
return `<li>${member.login}</li>`;
})
.join("");
})
.catch((error) => {
console.error('Error fetching members:', error);
});
</script>
</body>
</html>
异步编程最佳实践
1. 错误处理
go
// 使用catch处理Promise错误
someAsyncFunction()
.then(result => {
// 处理成功结果
})
.catch(error => {
// 处理错误
console.error('An error occurred:', error);
});
2. 并行执行多个异步操作
less
// 使用Promise.all同时执行多个异步操作
Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
])
.then(([users, posts, comments]) => {
// 所有请求都完成后执行
})
.catch(error => {
// 任何一个请求失败都会进入这里
});
3. async/await语法糖
vbnet
// 使用async/await使异步代码更易读
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching data:', error);
}
}
总结
JavaScript的异步编程模型虽然初看起来复杂,但理解其核心概念后,可以编写出高效、非阻塞的代码。关键要点包括:
- JavaScript是单线程的,使用事件循环处理异步操作
- setTimeout是基础的异步机制
- Promise提供了更强大的异步控制能力
- fetch是处理网络请求的现代API
- async/await语法让异步代码更易读
掌握这些概念和工具,将帮助你编写更高效、更可靠的JavaScript应用程序。