小白的JS学习之路(七)—— “Promise”
学习笔记整理,记录我从回调函数到Promise的学习过程,如果有理解错误的地方,欢迎大佬指正!
前言
学完了闭包和原型,接下来遇到了JavaScript的另一个"大BOSS"——异步编程和Promise。
说实话,刚开始学异步的时候,我是一头雾水的:为什么我的代码不按顺序执行?为什么数据获取不到?Promise、then、resolve、reject……这些概念之间到底是什么关系?
一、我是怎么理解"异步"的?
1.1 从操作系统课说起
上周上操作系统课,老师讲了进程的四大特性:虚拟、异步、并发、共享。
我突然联想到JS里的异步编程!老师说的并发性:在同一时间间隔内,执行多个任务。这不就是JS里异步编程的核心思想吗?
1.2 举个栗子🌰
我先试着写了个简单的例子:
javascript复制
let a = 1
setTimeout(() => {
a = 2
}, 1000)
console.log(a) // 输出:1(不是2!)
我的执行过程理解:
let a = 1是同步任务,马上执行setTimeout是异步任务,JS引擎说:“好的,我知道了,1秒后再来执行这个”- 但是!JS不会等着,而是继续执行后面的
console.log(a) - 所以输出的是
1,而不是2
💡 我的通俗理解:就像食堂打饭,前面的人还在挑菜(耗时任务),你可以先去拿餐具(不耗时的任务),不用傻等着。
1.3 JS为什么是单线程?
我查了资料才知道:
- JS运行在V8引擎里
- V8引擎默认只开启一个线程来执行代码
- 所以遇到耗时任务,只能先挂起,等主线程空闲再回来执行
我的类比:
- 浏览器新开一个tab页 = 开启一个新进程
- 这个进程里有多个线程通力合作(网络线程、渲染线程、JS执行线程等)
- 但是!JS执行只有一个线程,所以遇到耗时操作需要"异步"来处理
二、回调函数:我第一次遇到的坑
2.1 什么是回调?
我在MDN上看到的定义是:“把函数作为参数传递”。
但我更喜欢这样理解:当B函数需要依赖异步的A函数结果时,我们把B函数的调用放在A函数里面。
javascript复制
let a = null
function A() {
setTimeout(() => {
a = 100 // 1秒后才赋值
B() // 在回调里调用 B
}, 1000)
}
function B() {
console.log(a) // 只有当 A 完成后,才能正确输出 100
}
A()
我的问题:这相当于"强行把异步捋顺成同步",虽然能解决问题,但代码写得很丑 😑
2.2 回调地狱(Callback Hell)
当我尝试用回调写复杂逻辑时,代码变成了这样:
javascript复制
// 假设我们要依次完成:相亲 → 结婚 → 生娃
xq(function() {
marry(function() {
baby(function() {
// 还能再嵌套吗?能!但代码已经没法看了
})
})
})
我的崩溃瞬间:
- ❌ 代码像楼梯一样往右歪,看着眼晕
- ❌ 报错时找不到是哪个环节出问题
- ❌ 想改逻辑?抱歉,请做好重构的准备
三、Promise:我的救星!🌟
3.1 Promise是什么?
我在MDN上看到的定义是:“Promise 是一个表示异步操作最终完成或失败的对象。”
我的理解:Promise就像一个"承诺",它有三种状态:
pending:待定状态(正在进行中)fulfilled:已成功状态(承诺兑现)rejected:已失败状态(承诺失败)
🎯 生活例子:就像你向女神表白,女神说"我考虑一下"(pending),要么"好的"(fulfilled),要么"你是个好人"(rejected)。
3.2 我的第一个Promise代码
我照着MDN的示例,写了第一个Promise:
javascript复制
function xq() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('刘局相亲成功')
resolve() // 通知后续:我成功了!
}, 2000)
})
}
function marry() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('刘局结婚了')
resolve()
}, 1000)
})
}
function baby() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('刘局生了孩子')
resolve()
}, 1000)
})
}
我的理解:
new Promise()创建一个Promise对象resolve是"兑现承诺"的函数reject是"拒绝承诺"的函数- 在异步操作成功后调用
resolve()
3.3 Promise链式调用(解决回调地狱)
我以前的写法(回调地狱) :
javascript复制
xq(function() {
marry(function() {
baby()
})
})
现在用Promise(链式调用) :
javascript复制
xq()
.then(() => {
return marry() // 重要:一定要return!
})
.then(() => {
baby()
})
.catch(() => {
console.log('刘局相亲失败')
})
输出顺序:
code复制
刘局相亲成功
(等待2秒)
刘局结婚了
(等待1秒)
刘局生了孩子
我的感受:
- ✅ 代码像同步一样从上往下读,太爽了!
- ✅ 错误处理集中(catch捕获所有失败)
- ✅ 可维护性强,想加逻辑直接加
.then()
四、深入理解:我尝试手写Promise
为了真正理解Promise,我尝试写了一个简版:
javascript复制
function Promise(fn) {
this.state = 'pending' // 初始状态:待定
this.arr = [] // 存储 then 中的回调函数
const resolve = (res) => {
this.state = 'resolved' // 状态变为:成功
// 执行所有存起来的回调函数
this.arr.forEach(fn => fn(res))
}
const reject = () => {
this.state = 'rejected'
}
fn(resolve, reject) // 执行传入的函数
}
我的理解:
new Promise()得到一个状态为pending的对象.then(foo)会把foo存到this.arr数组里- 当
resolve()被调用时,Promise状态改为成功,并执行所有存起来的回调函数
💡 我的感悟:原来Promise的核心就是"状态管理 + 回调函数队列"啊!
五、实战中遇到的坑(我的血泪史)
坑1:忘记return!
javascript复制
// ❌ 我的错误写法
xq().then(() => {
marry() // 没有 return,链式调用会断!
})
// ✅ 正确写法
xq().then(() => {
return marry() // 返回 Promise,链式调用继续
})
我的教训:不return的话,下一个 .then() 拿不到Promise对象,代码就断开了!
坑2:错误处理
javascript复制
// 方法1:catch捕获(推荐)
xq()
.then(() => marry())
.then(() => baby())
.catch((err) => {
console.log('出错了:', err)
})
// 方法2:then的第二个参数
xq()
.then(() => marry(), (err) => {
console.log('出错了:', err)
})
我的选择:推荐用 .catch(),因为它能捕获整个链式调用中的所有错误,更清晰。
坑3:Promise.all vs Promise.race
javascript复制
// Promise.all:所有都成功才成功
Promise.all([xq(), marry(), baby()])
.then(() => console.log('全部完成!'))
// Promise.race:谁快用谁
Promise.race([xq(), marry(), baby()])
.then(() => console.log('有一个完成了!'))
我的理解:
Promise.all:等所有人都到齐才开会(全部成功)Promise.race:谁跑得快谁赢(第一个完成的)
六、我的学习总结
| 方式 | 我的评价 | 适用场景 |
|---|---|---|
| 回调函数 | 简单但难维护 | 简单异步操作 |
| Promise | 链式调用太爽了 | 大多数异步场景 |
| async/await | 还没学,据说更爽 | 复杂异步逻辑 |
我的学习路径:
- 先搞懂异步和回调的问题(踩坑)
- 学会Promise的基本用法(then/catch)
- 多写例子,体会链式调用的优雅
- 尝试手写简版Promise,理解原理
- 下一步:学async/await!
写在最后
Promise是前端异步编程的基石,虽然我一开始也很难理解,但多写多练就能掌握。
我的学习资源:
- ✅ MDN Web Docs - Promise(强烈推荐!官方文档最权威)
- ✅ 阮一峰《ES6 标准入门》(写得通俗易懂)
- ✅ 各位大佬的掘金文章(感谢分享!)
我的建议(仅供参考):
- 不要死记硬背,要理解原理
- 多写例子,从简单到复杂
- 遇到问题先查MDN,再查掘金文章
- 尝试手写简版,加深理解
最后:这篇文章是我个人的学习笔记,如果有理解错误的地方,欢迎大佬指正!我们一起进步 💪
参考资料:
- MDN Web Docs - Promise
- 阮一峰《ES6 标准入门》
- 各位大佬的掘金分享
关键词:#JavaScript #ES6 #Promise #异步编程 #小白学习笔记
PS:如果觉得这篇文章有帮助,欢迎点赞收藏!有问题也可以在评论区留言,我会尽量回复(虽然我也是小白哈哈 😊)
🔗 系列文章:
- 小白的JS学习之路(三)—— JS类型
- 小白的JS学习之路(四)—— 闭包
- 小白的JS学习之路(五)—— 原型
- 小白的JS学习之路(六)—— this
- 小白的JS学习之路(七)—— Promise(本文)