从 savedPerson 说起:我终于理解了 Promise.then
一开始我以为我懂 Promise。
then 嘛,不就是“异步回调”吗?
链式调用,拿结果,用就完了。
直到我在写 Full Stack Open 的 Phonebook 后端时,被一个变量狠狠干了一下。
一个看起来很正常的代码
写的代码是这样的,因为是照着他的例子改得,写的时候并没有感觉很复杂:
Person.findOne({ name: body.name })
.then(existing => {
if (existing) {
return res.status(400).json({ error: 'name must be unique' })
}
const person = new Person({
name: body.name,
number: body.number,
})
return person.save()
})
.then(savedPerson => {
if (savedPerson) res.json(savedPerson)
})
一切看起来都很合理。
直到我开始认真看这一句:
.then(savedPerson => {
if (savedPerson) res.json(savedPerson)
})
我当时脑子里的第一个问题
savedPerson 是哪来的?
注意,这个变量在此之前:
- 没有声明过
- 没有赋值过
- 甚至在代码里从来没出现过
那问题来了:
JavaScript 是怎么判断
savedPerson是不是undefined的?
一开始我完全想歪了
我下意识以为:
savedPerson是某种“内置变量”- 或者 Mongoose 偷偷塞了点魔法
- 或者
.then里面有特殊规则
但这些都不对。
真相其实很“简单”,但不直观
关键在于一句话:
.then后面的函数,不是立刻执行的,而是“注册回调”
换句话说:
.then(savedPerson => { ... })
本质等价于:
.then(function (savedPerson) {
...
})
而这个函数—— 只有在前一个 Promise resolve 之后,才会被调用。
那 savedPerson 到底是谁给的?
不是 JavaScript 凭空变出来的。 是 Promise 在 resolve 的那一刻,把值当参数传进来的。
就像这样(概念化):
promise完成后: callback(resolve出来的值)
也就是说:
- 如果你
return person.save()→ resolve 的是 保存成功的文档对象 - 如果你
return res.status(...).json(...)→ 实际上 resolve 的是 undefined
于是:
(savedPerson) => { ... }
里的 savedPerson:
- 有时候是对象
- 有时候是
undefined
我真正“想通”的那一刻
当我意识到这一点时,很多东西突然一起通了:
.then不是“下一行代码”- 它是 “等这件事做完后,再执行”
then里的参数不是“提前存在的变量”- 而是 Promise resolve 时,临时传进来的函数参数
从这一刻开始:
savedPerson不再神秘undefined不再诡异- Promise 链也不再像黑盒
后来我才发现:我以前一直在“用 Promise”,但没真正理解它
我以前只是知道:
- Promise 是异步
- then 可以拿结果
但现在我终于明白:
Promise 的核心不是异步,而是“状态变化 + 回调注册”。
评论区
评论加载中...