很多人说这个没用,还嘲讽深入理解,没有解决麻烦和任何问题
我举个最简单的例子,python协程的async await,代码如下:
import asyncio
async def sleep(seconds):
await asyncio.sleep(seconds)
async def main(num=0):
# 并发执行多个异步任务
print(num)
await sleep(0.0001)
await main(num + 1)
asyncio.run(main())
输出到1000就会堆栈溢出,而用js的promise实现一样的函数,却不会
然而一旦把sleep去掉,就会立马堆栈溢出
function sleep(time){
return new Promise(resolve => setTimeout(resolve, time));
}
async function main(num=0){
console.log(num)
//去掉sleep会堆栈溢出
await sleep(1);
await main(num+1)
}
main()
因为js中的await实际上等效于then,也就是下面的代码,每次循环都是新的任务提交到事件循环队列,所以不会堆栈累加:
async function main(num=0){
console.log(num)
sleep(1).then(()=>{
main(num+1)
})
}
导致函数堆栈溢出的因素都可以说成不重要。没有任何意义,到底是自己没有认真学,还是真的不重要,各位自行判断吧
不要在说有什么用,有什么应用场景了,手写apply call bind这些面试题有应用场景吗?
单纯为了兴趣研究下,就跟普通promise输出顺序的面试题一样,也可以写个类似的
async function main() {
await {
then(func) {
console.log(1)
setTimeout(func,0);
console.log(2)
}
}
console.log(3)
}
main()
``
101
xz410236056 20 天前
@wefgonujnopu #15 你这言论让我想起前几天看的一篇文章,用 C 语言搞一堆优化魔法为什么没 RUST 快,因为 C 语言没有跟进 CPU 的分支预测、simd 等特性。意思是,你搞这玩意(在很多人看来)毫无意义,真喜欢研究就去给 ECMAScript 提交标准呀(你所谓的那些实际执行什么的,完全不如一个新的研究、新的指令、编译器优化带来的提升大)。
|
102
wefgonujnopu OP @deadpl 是没关系,python 只是为了对比,正常语言都是这样的,但是 js 的就和 await 有关系,所以 js 不正常
|
103
wefgonujnopu OP @xz410236056 很多人看来无意义就是无意义吗,我觉得有意义,而且手写 promise 比这个难多了,面试也会问 js 的宏任务微任务执行过程,是很常见的问题
|
![]() |
104
lizhenda 20 天前
笑死,这问题我在面试时还真问过,其实大多数中高级前端都基本能回答出来,一下没反应过来引导下也是可以,只是考查对 promise 实现的理解以及 js 事件循环有没有概念 await/async 本质是啥,编译后的产物有没有看过之类的。
|
![]() |
105
kongcc 20 天前
|
![]() |
106
lizhenda 20 天前
@lizhenda 还记得好多年前会问下在 es6 没出来前,用 js 自己怎么实现一个 class 的思路。最近这些年就只问 vue/react 之类的理解和实践了。
|
107
wefgonujnopu OP @lizhenda 这么巧,还真有人问过,这个确实不难,只要理解透彻 promise 的都能回答出来,不过貌似 v2 很多人不会,一堆人嘲讽
|
108
xz410236056 20 天前
|
109
wefgonujnopu OP @xz410236056 没什么目的啊,v2 不就是程序员交流的吗,而且也没筛选出来知道的人啊,就一个人回答正确了,其他的也就没回复了,正常交流技术而已
|
110
mizuki9 20 天前
确实没啥用,thenable 和 理解透彻 promise 有关系吗,知道 thenable 就透彻了?透彻在哪?
作为考察前端知识的了解程度是可以的。 |
111
wefgonujnopu OP @mizuki9 我说的是,理解透彻了,肯定知道 thenable 啊,你不知道 thenable 能算理解透彻? 但是知道 thenable 不代表理解透彻
|
![]() |
112
wangtian2020 20 天前
点开帖子,浏览问题,思考一会,发现不会
勃然大怒,全文搜索,没人骂 op ,失望离开 —— 像 promise.then 那样,await 允许我们使用 thenable 对象(那些具有可调用的 then 方法的对象)。这里的想法是,第三方对象可能不是一个 promise ,但却是 promise 兼容的:如果这些对象支持 .then ,那么就可以对它们使用 await https://zh.javascript.info/async-await |
113
johnnyyeen 20 天前
大哥,递归一般是禁止在生产环境使用的,我记得我刚去腾讯那会,解决了一个前任的诡异 bug ,就是因为递归调用导致栈溢出。
这是最基本的常识....... |
114
wefgonujnopu OP @johnnyyeen 说的是对 promise 的理解,递归是次要的,而且不同公司规定不一样,怎么可能全部禁用递归,递归也确实有优点,比如可读性高,代码简洁
|
115
johnnyyeen 20 天前
@wefgonujnopu 除了教学基本没优点,就如此简单。
|
116
johnnyyeen 20 天前
生产环境用递归的,见一个砍一个。
|
117
wefgonujnopu OP @johnnyyeen 就是教学用的,跟手写 promise 一样,上面已经说了
|
118
bowencool 20 天前
@Zhuzhuchenyan #1 涨姿势了
|
![]() |
119
enpitsulin 20 天前
就算用 Promise/PormiseLike/Thenable 就本质一个 callback 的 语法糖,做不到不阻塞线程也配叫 sleep ?没睡醒?
[Atomics.wait]( https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Atomics#%E7%AD%89%E5%BE%85%E5%92%8C%E9%80%9A%E7%9F%A5_2) |
120
wefgonujnopu OP @enpitsulin 你说的啥,promise 本身就是不阻塞线程的
|
![]() |
121
AoEiuV020JP 20 天前
不用看都知道帖子里的回复是“对人不对事”,明显主楼高高在上的态度惹人不快,回帖是找茬的没人想和你讨论什么,
|
![]() |
122
Mandelo 20 天前
@wefgonujnopu #2 2025 了善用 AI ,
|
![]() |
123
Mandelo 20 天前
@wefgonujnopu #2
function sleep(ms) { return { then: function (resolve) { setTimeout(resolve, ms); } }; } ✅ 用法: async function run() { console.log('start'); await sleep(1000); // ✅ 正常延迟 1 秒 console.log('after 1 second'); } run(); 虽然没有写 new Promise(...),但依然是一个“类 Promise 对象”,这是唯一能让 await 起作用的方法。 |
![]() |
124
hzzhzzdogee 20 天前
@Torpedo true
|
125
wefgonujnopu OP @AoEiuV020JP 这样帖子才能火,这叫逆向思维,不然就是无人问津了
|
126
unused 20 天前 via Android
await 会为 Thenable 创建 Promise
|
![]() |
127
ykrank 20 天前
@wefgonujnopu #47 imgur 都打不开的开发者...符合会问这种问题的刻板印象
|
128
taotaodaddy 20 天前
讨论的还挺热烈,不管怎么样,gemini 4o qwen 都可以,grok 不行,老马得加把劲了
|
129
wefgonujnopu OP @ykrank 懂了."data":{"error":"Imgur is temporarily over capacity. Please try again later."},"success":false,"status":403} 所以 imgur 过载是我的问题
|
![]() |
130
Plumbiu 20 天前
跟楼主说一下,楼主的例子其实现实中也有类似的,例如轮询,对象的毕设用的 lvgl ,里面的回调事件就是 30ms 轮询监听的,另外我之前也写过监听窗口句柄变化的时尚小垃圾,也是过 1s 左右轮询一次。楼上觉得没实际意义大概率是见识太少了
|
![]() |
131
jiangzm 20 天前
这个考查不了什么, 知道不加分不知道不减分
|
![]() |
132
jiangzm 20 天前
楼主刚知道的一个基础知识点,准备用来做面试题, 笑死人,哈哈哈哈😂😂😂
|
![]() |
133
siweipancc 20 天前 via iPhone
震惊我后端仔了
|
134
maolon 20 天前
hmmm 这种茴香豆的茴几种写法的东西除了考八股真有人会写到业务代码里去?
|
![]() |
135
flyn 20 天前 via Android
虽然好多人在嘲讽楼主,但我还真是的涨见识了,因为我是业余的,和上面某个楼的前端新手的知识储备类似
|
![]() |
136
mightybruce 20 天前
js 尾调用优化了解了解, 把递归变成循环。
await 就是按照顺序执行,它就是阻塞, 我都没看到有人提到 python 中是 async.gather js 中是 promise.all 来做 如果不用 promise 还得研究一下。 |
137
wefgonujnopu OP @mightybruce 我服了,js 没有尾调用优化好吗,你自己试试,不在末尾的 await,也不会触发堆栈溢出的
|
138
wefgonujnopu OP @maolon 本来就是考八股的,什么时候说写业务了
|
![]() |
139
accelerator1 20 天前
LZ 既然摆出了考验别人的姿态,那就要做好被别人质疑的准备,事情都有好坏方面。
题目要求是 await sleep ,大部分想到的都是 thenable 对象了,楼上已经有人写出来了。 原因 LZ 自己也说了,python 那个不行就是因为它的 await 不像 js 会清除调用栈变为事件循环。 其实用阻塞 sleep 也行,只要有 async/await 关键字,就能清除调用栈保证不会栈溢出。 ``` function sleep(ms) { const start = Date.now(); while (Date.now() - start < ms) { // 阻塞 } } async function main(num=0){ console.log(num) //去掉 await 会堆栈溢出 await sleep(1); await main(num+1) } main() ``` |
140
wefgonujnopu OP @accelerator1 是,但是题目已经说了,不能用阻塞 sleep
|
![]() |
141
accelerator1 20 天前
@accelerator1 #138 我觉得这类问题挺好的,那些有异议的人应该先写出来、解释清楚再去反驳,"Talk is cheap, show me the code"。
|
![]() |
142
accelerator1 20 天前
@wefgonujnopu #139 我也只是说明原理,并不是回答问题,在 js 单线程实现下,不阻塞的 sleep 只能宏任务 api ,相对不是那么准而已;想要准确的 sleep ,只能阻塞方式。题目说是实现 sleep ,其实更关注的其实是避免栈溢出。
|
![]() |
143
zangbianxuegu 19 天前
主题目 thenable 考察和附言的阻塞、堆栈溢出没什么关系。
为什么 js 的 sleep 不会导致堆栈溢出,这其实是和**事件循环**相关,**事件循环是浏览器的机制**。 可以看我这篇文章,以及里面大佬的视频演讲: https://mp.weixin.qq.com/s/MzAAa4ohk-75BHqGRH1XWQ 简单说因为 sleep 实现用的是 setTimeout ,比如: ```js function loop() { setTimeout(loop, 0); } loop(); ``` 这段代码永远不会导致浏览器卡死,setTimeout 创建任务加入任务队列,setTimeout 执行完会让出主线程控制权,进行渲染和其他任务。 |
![]() |
144
zangbianxuegu 19 天前
既说了不能阻塞线程,又觉得它不会造成堆栈溢出是不对的。这不是矛盾吗?
|
145
wefgonujnopu OP @zangbianxuegu 你错了,和 setTimeout 没关系,你看这段代码有 setTimeout 么,为什么也不会溢出
··· async function foo() { return 1 } async function main(num = 0) { //去掉 foo 会堆栈溢出 await foo() await main() } main() ··· |
![]() |
146
zangbianxuegu 19 天前
@wefgonujnopu #145
不错,我说矛盾的说法也不准确。微任务确实不阻塞代码执行,也不会造成调用栈溢出。 有 `await foo()` 不会导致堆栈溢出是因为,await 创建微任务,main() 当前的调用栈被清空,每一次都会被清空不会累加,所以不会出现:Maximum call stack size exceeded 以上是在 Node 环境中。 在浏览器环境中,有没有 `await foo()` 都会导致浏览器的卡死,因为阻塞渲染。 |
147
chanderbing 19 天前
感觉自己实现过 promise 的都能一秒想到吧,因为实现的时候就要对 thenable 对象进行处理。https://github.com/childrentime/wheel/blob/main/src/promise/index.js#L139-L158
|