在前端开发的日常中,我们常常需要与服务器通信、处理异步任务。今天的学习内容围绕着 Ajax、Promise、fetch 以及 JavaScript 内存模型 展开,这些都是构建现代 Web 应用不可或缺的核心知识。让我们一起梳理并深入理解这些概念吧!✨
🔄 传统 Ajax 与现代 fetch 的对比
Ajax(Asynchronous JavaScript and XML)
- 基于 回调函数 实现异步请求。
- 使用
XMLHttpRequest对象,代码冗长且嵌套复杂(“回调地狱” 😵)。 - 需手动处理状态码、响应类型等细节。
// 传统 Ajax 示例
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/data');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send();
fetch API
- 基于 Promise 设计,语法简洁优雅 ✨。
- 天然支持链式调用(
.then().catch()),逻辑清晰。 - 默认不发送 cookies(需显式配置),更符合现代安全规范。
// fetch 示例
fetch('/api/data')
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error('请求失败:', err));
💡 结论:
fetch是对 Ajax 的现代化封装,更适合现代开发流程。
🧩 手写一个支持 Promise 的 getJSON 函数
既然 fetch 如此好用,那能否用传统的 XMLHttpRequest 封装出一个返回 Promise 的 getJSON 函数呢?当然可以!
function getJSON(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.setRequestHeader('Accept', 'application/json');
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300) {
try {
resolve(JSON.parse(xhr.responseText));
} catch (e) {
reject(new Error('JSON 解析失败'));
}
} else {
reject(new Error(`请求失败: ${xhr.status}`));
}
};
xhr.onerror = () => reject(new Error('网络错误'));
xhr.send();
});
}
// 使用
getJSON('/api/user')
.then(user => console.log(user))
.catch(err => console.error(err));
这个函数将传统的回调式 Ajax 转化为 Promise 风格,实现了“异步变同步”的流程控制 🧠。
🧱 深入理解 Promise
Promise 是 JavaScript 中处理异步操作的事实标准,它有三种状态:
- pending(初始状态)
- fulfilled(成功,调用
resolve) - rejected(失败,调用
reject)
通过 .then() 处理成功结果,.catch() 捕获错误,使异步代码更接近同步写法:
new Promise((resolve, reject) => {
setTimeout(() => resolve('搞定!'), 1000);
})
.then(msg => console.log(msg)) // 输出:搞定!
.catch(err => console.error(err));
✅ 关键点:Promise 让异步逻辑线性化,避免了层层嵌套的回调。
💾 JavaScript 内存模型:栈 vs 堆
理解变量存储方式对写出高效代码至关重要:
-
栈内存(Stack)
- 存储 基本数据类型(如
number,string,boolean)。 - 值直接存储,访问速度快 ⚡。
- 变量提升(hoisting)发生在编译阶段,为变量预留空间。
- 存储 基本数据类型(如
-
堆内存(Heap)
- 存储 引用类型(如
object,array,function)。 - 栈中保存的是指向堆中对象的 引用地址。
- 对象在堆中分配,内存不连续,访问稍慢。
- 存储 引用类型(如
let a = 10; // 栈
let obj = { name: 'Alice' }; // obj 在栈,{ name: 'Alice' } 在堆
let b = obj; // b 和 obj 共享同一堆地址(引用拷贝)
⚠️ 注意:修改
b.name会影响obj.name,因为它们指向同一个对象!
🛌 手写 sleep 函数(补充知识点)
虽然你上传的 3.html 只写了“手写sleep函数”,但我们可以实现一个基于 Promise 的 sleep,用于模拟延迟:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用
async function demo() {
console.log('开始');
await sleep(2000);
console.log('2秒后执行');
}
这在测试、动画或节流场景中非常实用!🌙
🎯 总结
今天我们从 Ajax 的局限性 出发,拥抱了 Promise 和 fetch 带来的简洁与强大;通过封装 getJSON,掌握了如何将传统异步操作现代化;同时深入理解了 JavaScript 的内存机制,为写出更健壮的代码打下基础。
前端世界日新月异,但底层原理始终如一。掌握这些核心概念,你就能在任何框架(React、Vue、Svelte...)中游刃有余!🚀
继续加油,未来的你一定会感谢现在努力的自己!💪🌈