JavaScript 中的 Promise 跟异步有关系吗?还是我的理解有问题?谁能把 Promise 解释清楚? Promise 的正确用法应该是什么样的?

174 天前
 burnbrid

感觉 Promise 跟异步没有关系啊!我理解的异步是 ajax 这样的,ajax 将请求发出去之后,代码就继续往下执行了,等到 ajax 收到响应结果了,再回头执行 ajax 的回调函数,这才是异步。不是说你指定了回调函数就是异步。Promise 构造函数里面的代码是同步执行的,假如在 Promise 构造函数里面执行一个 10 万次的循环,主线程会等这 10 万次执行结束之后,才会继续执行下一行代码,这叫异步吗?异步跟回调函数没有一点关系。 异步就是不在主线程里面执行。

const ps = new Promise(function name(resolve, reject) { let i = 0; while(i<1000000){ i = i+1; console.log('i=',i); } }); console.log('promise 是异步吗?');

等上面这 100 万次循(最耗时的操作)环执行完,我还有必要通过 then 去指定回调函数吗?我直接执行回调函数就可以了,根本不需要通过 then 去执行回调函数。

5452 次点击
所在节点    JavaScript
51 条回复
cookii
174 天前
异步和并行是两个概念,单线程也可以异步。
chiaf
174 天前
把异步代码放进去

Promise 本身不是异步,他只是个对象,一个容器,用于封装和管理异步操作。

设计 Promise 不是为了解决回调地狱的问题吗?
iMusic
174 天前
我觉得 Promise 主要解决的是回调变成了链式。

关于你举例的这个问题,看下 JS 的事件循环机制,Promise 相关哪些是微任务。
ShadowPower
174 天前
Promise 不提供异步机制,而是管理异步流程
renmu
174 天前
promise 不是异步,异步的是网络请求,io 操作
Linho1219
174 天前
Promise 构造函数传进去的回调当然是直接同步执行的,但这个回调里面可以有网络请求,或者任何其他的“传统”的通过回调实现的异步操作,这些传统异步操作在成功或失败的时候调用 resolve reject ,实现异步代码执行结果的分发。
注意分发这个词。Promise 解决的是异步结果的分发问题,方便挂载回调而已,它本身只是一个容器。你可以将其理解为“大闸蟹券”,拿着券去领大闸蟹,但不意味着拿券和拿蟹是异步的(有螃蟹的时候也可以发券)。
因此 Promise 有两种使用方法:一种就是异步操作的 API 本身就是用 Promise 封装的,这样可以很方便地挂载回调;另一种是将传统的回调式 API 封装成 Promise ,这样可以更方便地挂载回调
yor1g
174 天前
promise 是回调的标准封装而已
Linho1219
174 天前
此外你的理解还有一个严重问题,异步回调还是在主线程中执行的,JS 是单线程的( worker 除外)。可以看看我写的这篇文章 https://notes.linho.cc/s?q=c876458647
ShadowPower
174 天前
另外,在不在主线程里执行并不能用来判断是不是异步。异步一般跟 IO 有关,主要用于解决线程会被 IO 阻塞的问题。
这里的 IO 可以是文件,可以是网络,也可以是用户的输入。
当然,也可以用多线程实现异步,但是并发不会很高。
june4
174 天前
你不看 resolve,reject 这二个参数吗,这是可以异步调用的,比如在用户事件回调/网络回调中,这就是异步啊。且你在 await 这个 promise 时会等到这二个参数被调用后才会往下执行,这又解决了回调地狱。
duanxianze
174 天前
Promise 本质就是语法糖
bsg1992
174 天前
异步 和并行不是一回事的
Promise 解决的函数回调回调地狱的问题
且 JS 本身单线程 靠的是 event loop 。
而你说的这个 是多线程, 在目前浏览器中 只有 worker 和网络请求是单独的线程执行的
panyang
174 天前
所实话,你的理解没有什么大问题。new Promise 中的代码确实是同步执行的,但是传入的 resolve 或 reject 函数会异步触发。

对于你的困惑,应该是你忘了 resolve 或 reject 函数会异步触发。
Linho1219
174 天前
@duanxianze Promise 哪里是语法糖???
luohechen
174 天前
@duanxianze async await 才是语法糖
PTLin
174 天前
你要明白 js runtime 的单线程 事件循环模型才能真正的了解 promise 和 js 的 async 。
搜索关键词:javascript 事件循环
leonshaw
174 天前
你最终要调用原生的异步方法才是异步
ns09005264
174 天前
我想 javascript 的异步大概是这样发展的:
1. 最开始是 xmlhttprequest ,然后通过回调函数处理异步结果。
2. 之后添加了 Promise ,通过链式调用来解决回调地狱,本质就是一个“工具类”,用户也可以手写 Promise ,在语法上没什么特别的。
3. 添加了 await 和 async 关键字,专门在语法层面改善了 Promise 的链式调用地狱。
现在的情况是,用来解决回调地狱的 Promise ,被 await 和 async 进一步取代了。


还能用到 Promise 的地方,这里有一个例子,有许多图片 node 共用一张精灵图,而图片 node 是根据用户滚动视图懒加载的,会先于精灵图的加载展示在页面文档里,因此利用了 Promise 给图片 node 一个保证,等你要展示图片的时候,再叫我。

https://github.com/MapoMagpie/eh-view-enhance/blob/d77e0655cff35818141b5e6e5246221b1fb12d74/src/platform/ehentai.ts#L211
在 211 行给 node.delaySrc 设置了 Promise 属性,但是在构造的时候将 Promise 里的 resolve 和 reject 拿走了,接着在 215 行的异步操作的回调函数里去执行 resolve 或 reject 。

最后在某个将来时刻再使用 node.delaySrc
https://github.com/MapoMagpie/eh-view-enhance/blob/d77e0655cff35818141b5e6e5246221b1fb12d74/src/img-node.ts#L146
iOCZS
174 天前
promise 是微任务队列,async&await 是协程
angrylid
174 天前
同步代码是逐行往下执行的,碰到网络请求必须等待结果,把后面的计算都阻塞了。
伪代码如下
```
var image = loadResourceSync('/assets/example.png')

canvas.draw(image) // 必须等待上一行得到结果才会往下执行
// 假设后面还有很多代码,都得等着这个网络请求
```
这样肯定是不合理的,除依赖这个图像资源的代码之外,其他的代码无须等待这个网络请求。
于是应该是
```
loadResource('/assets/example.png', (err, data) => {
// 这个函数会在网络请求完毕后调用
if(err) {
alert(err)
return
}
canvas.draw(data)
})

element.innerText = 'Hello World' // 此代码不会等待上面资源加载

```
但是这样很容易写出回调地狱,像这样
```
loadResource('/assets/example.png', (err, data) => {
loadResource('/assets/example2.png', (err, data) => {
loadResource('/assets/example3.png', (err, data) => {
// ...
})
})
})

```

Promise 是一个状态机,帮助你把回调地狱改造成链式调用。

大概像这样
```
var loadResource = (url) => new Promise((resolve, reject) => {
loadResource(url, (err, data) => { if(err) reject(err) else resolve(data) }
})

```
然后你就可以愉快地用链式地狱来替代回调地狱
```
loadResource('/assets/example.png')
.then((data) => {
// ...
return loadResource('/assets/example2.png')
})
.then((data) => {
// ...
return loadResource('/assets/example3.png')
})
```


不严谨地概括一下就是这样,有空你去看一下如何手搓 Promise ,代码其实并不多,就知道怎么回事了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1118623

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX