百科问答小站 logo
百科问答小站 font logo



Promise 不能被取消,真的算是它的缺点吗? 第1页

  

user avatar   catchen 网友的相关建议: 
      

不是。TC39 曾经有人提案过取消 Promise 的 API,但最后讨论一番后作者撤销了提案。以下是 TC39 GitHub 上的提案:

已经有人写过长文为什么 Promise 不应该有可取消的 API:

根据 TC 历史讲故事的工作交给 @贺师俊 吧,我直接说一下为什么 Promise 不能被取消吧。


首先,Promise 被设计为 eager,也就是一旦启动就立即开始执行,尽快获得执行结果,而不是等到你需要结果时才开始执行。这种设计使得 Promise 的取消往往毫无意义。

这种 eager 执行的方式,就如同你下单后立即现金结算然后发货一样,钱你肯定是要不回来的,货物送到后你也不可能要求送回仓库去,你拒收就相当于把货物在原地扔掉。

类似地,Promise 一旦开始执行,底层的软硬件资源开销就已经产生了,没有任何办法撤回。举个具体的例子,你发了一个网络请求,无论如何这个网络请求都会发完,无论如何服务器返回的数据都会收完,底层不提供任何接口给你中断和服务器的连接。

所以,如果你取消 fetch 返回的 Promise 实际上什么都撤销不了。上层调用 fetch 的复杂异步操作,给你一个可取消的 Promise,实际上也是无法撤销底层的 fetch。如果复杂操作涉及多次 fetch,让你取消实际上撤销了哪个 fetch,哪个 fetch 已经撤销不了,也无法明示。

如果取消 Promise 的语义如此不明确,那还是别给你取消的 API 好了。


要有明确的可撤销语义,很快你发现你重新发明了 Observable,那你为什么不直接用 Observable 呢?

回到上面的例子,你有一个复杂的异步操作,需要多阶段调用 fetch,封装成 Observable 就可以一步一步往前走,你不让它往前走时,剩余步骤的开销就不会发生。所谓的取消,就是不再驱动它往前走,这一个变量就能控制。


在 Promise 广泛应用之后,再引入取消的 API 就会破坏兼容性。一个 Promise 启动后,原本 await 只预期 resolve 或 reject 两种终极状态。现在多一个 cancel 的终极状态,原来的代码处理不了,怎么办?

你会说你不取消 Promise 就能保证兼容,但你能保证你写的 Promise 内部嵌套的别人的 Promise 呢?例如一个第三方库,支持取消当前所有网络请求的 Promise,你怎么办?


如果你真的需要一个可以取消的 Promise,你用两个正常的 Promise 就能捏出来一个。第一个 Promise 是正常使用的 Promise,代表你要执行的异步操作状态。第二个 Promise 代表第一个 Promise 是否被取消过,取消时它就 resolve,但一旦第一个 Promise 完成了它就被自动 reject 掉。这时候你就手工捏出来了一个有三个终极状态的 Promise。




  

相关话题

  &&-||能完全代替所有可以使用if-else的情况吗? 
  网上都说操作真实 DOM 慢,但测试结果却比 React 更快,为什么? 
  为什么很多明知js的OOP是假的,还不厌其烦地实现,而不使用OLOO风格? 
  为什么很多技术都觉得前端很简单? 
  大型公司里外包员工和正式员工有什么区别? 
  避免使用 eval、new Function 的方法可以降低 XSS 攻击的风险吗?为什么? 
  TypeScript 不适合在 vue 业务开发中使用吗? 
  setTimeout 真的有用吗? 
  “云原生”(Cloud Native)和前端开发的技术结合点在哪里? 
  如何看待百度要求内部全面停止使用 React / React Native? 

前一个讨论
资本家为了盈利不是不惜一切代价吗?那为什么作为工业品的显卡他们不愿扩大产量呢?
下一个讨论
为什么CPU/GPU的温度会在一瞬间波动十度以上?





© 2025-03-25 - tinynew.org. All Rights Reserved.
© 2025-03-25 - tinynew.org. 保留所有权利