前言

前两天在吃饭时,同事忽然抛出一个问题,Promise 的真正意义是啥? 对话场景如下:

:Promise 的意义是啥?

:为解决回调地狱,增强了代码可读性,改善了代码结构

:这是大家都知道的,仅仅是为了这个吗? Promise 解决了什么回调不能解决的问题,如果仅仅是为了回调地狱和可读性,Promise从社区走向ES6标准这么长的历程是不是有点小题大作?

:宿主(浏览器,V8)发起的叫做宏观任务(Macro Task)比如事件,setTimeout。JavaScript引擎本身发起的叫做微观任务。Promise 正是赋予了 js 引擎发起微观任务(Micro Task)的能力。

:so what ? 这只是一种实现方式的不同,Promise 成为标准前,大部分实现它的库的都是用 setTimeout 模拟的,至少说明绝大多数用到 Promise 的场景都可以用 setTimeout 替换。况且 Promise 的一大堆 then 也不见得多好看。。

: 咳咳,解决回调地狱至少是 Promise 从社区兴起的一条重要主线,正因为 Promise 还是有繁琐的地方,所以 ES7 又推出了 async/await,作为 Promise 的一个语法糖。从回调地狱 -> Promise -> async/await,不正是体现了可读性可维护性这条主线吗?

他: 感觉还是分量不足。。。

:Promise 还提供了很多牛逼的 api,比如 race, all 等,算是一整套处理异步的解决方案吧。

他: 有点道理,不过觉得还是没有 get 到那个叫人虎躯一震的终极意义。。

:看来本次午饭面试我以失败告终了。。。?

:哎。。。探讨探讨,回去再查查

Promise 深层意义

吃好饭趁休息时间,好好的 google 了一把。大部分文章中对 Promise 的讲解都是基于上述我们对话中的角度,比如 Promise 的含义,使用,API介绍,宏观任务/微观任务。可以总结为是什么怎么用

关于为什么,有两篇文章说的很好:

O’REILLY出版的 你不知道的JavaScript 关于 Promise 的部分
You’re Missing the Point of Promises

Promise 是可信任的

言下之意即回调是有信任风险的,举个栗子:

假设我们在开发一个交易系统。当用户点击“确定”购买时,需要调用由某个分析追踪公司提供的第三方函数以便跟踪这个交易。

可能是为了提高性能,这是一个异步追踪的工具,这意味着我们需要传入一个回调函数,支付和展示感谢页面的逻辑在回调中做。

analytics.trackPurchase(purchaseData, function(){ chargeCreditCard(); // 支付displayThankyouPage(); // 展示感谢页面
});

看起来没有任何问题。然而半年后的某一天,老板忽然打电话过来,让你赶紧到办公室来。
原来一位客户购买了一次,信用卡却被刷了五次,他很生气,这可以理解。客服已经道歉并启 动了退款流程。

通过分析日志,原来是那个分析工具在出于某种原因(比如升级时的bug)把回调调用了五次而不是一次。类似于:

if (purchaseData) {callback(); callback();....callback();
}

在下次更新前,第三方库中的这个 bug 会一直存在。哪怕问题修复了,我也不会再信任这个库了。因此不得不自己动手搞一个防御性编程,加一些临时代码绕过这个 bug. 比如:

var tracked = false;
analytics.trackPurchase( purchaseData, function(){ if (!tracked) {tracked = true; chargeCreditCard(); displayThankyouPage();}
});

接下来看 Promise 是如何构建信用的:

还以上文的交易系统为例,如果这个第三方异步追踪工具用 Promise 实现,那么基本的调用方式应该是这样:

analytics.trackPurchase(purchaseData).then(function() {chargeCreditCard(); displayThankyouPage();
});

乍一看无非是把回调函数放到了 then 当中,似乎与回调方式并无什么不同。但是仔细想想你就会发现,Promise 的写法绝对不会发生反复支付那种 bug。原因就是回调实现中,回调函数的控制权在第三方手中,而 Promise 中回调的控制权在我们自己手上。

Promise 这种模式通过可信任的语义(resolve or reject)把回调作为参数传递,使得这种行为更可靠更合理。通过把回调的控制反转反转回来,我 们把控制权放在了一个可信任的系统(Promise)中,这种系统的设计目的就是为了使异步编码更清晰。

真正的回调地狱

上面例子中第三方库出错的原因是对回调的多个并发调用。这只是一种错误情形。头脑风暴一下,错误类型其实可能会有很多:

  • 调用回调过早(在追踪之前)
  • 调用回调过晚(或没有调用)
  • 调用回调的次数太少或太多(上小节遇到的问题)
  • 没有把所需的环境 / 参数成功传给你的回调函数
  • 吞掉可能出现的错误或异常

对于无法信任的工具的每个回调,我们将不得不做大量的防御性编程 (workaround) 来避免这些问题的发生。这才是真正的回调地狱!

小结

Promise 解决了我们因只用回调的代码而备受困扰的控制反转问题。

Promise 并没有摈弃回调,只是把回调的安排转交给了一个位于我们和其他工具之间的可信任的中介机制。

Promise 链也开始提供(尽管并不完美)以顺序的方式表达异步流的一个更好的方法,这有助于我们的大脑更好地计划和维护异步 JavaScript 代码。

Promise的真正意义--不只为回调地狱相关推荐

  1. Promise链式调用和解决回调地狱的ES7终极解决方法async,await

    promise链式调用 **then 是成功回调,只要在then后边return一个promise就可以继续then**<script type="text/javascript&qu ...

  2. Promise的用法及如何解决回调地狱

    主要谈及: 是什么,怎么做,如何实现 一.setTimeout函数依次执行的传统方法 function fn1(){setTimeout(()=>{console.log('fn1')},100 ...

  3. ES6 --- Promise深入学习(一)回调地狱,厄运金字塔带来的问题

    简介:回调 JavaScript 主机(host)环境提供了许多函数,这些函数允许我们计划 异步 行为(action).换句话说,我们现在开始执行的行为,但它们会在稍后完成. 例如,setTimeou ...

  4. 回调地狱以及解决回调地狱 - promise嵌套变链接 - 解决终极办法 - async 和 await

    回调函数? 当一个函数被当做参数传递时,这个函数就叫做回调函数-  callback 通常使用回调函数来处理异步代码 当异步代码执行结束后,需要执行的代码就要放在回调函数中 回调地狱? 当回调函数嵌套 ...

  5. 【Promise】基本使用+回调地狱+宏队列与微队列

    文章目录 前奏 1.函数对象 2.回调函数 3.Error 正题 1.基本使用 2.回调地狱 3.关键问题 4.async与await 异步队列 示例 前奏 1.函数对象 /* 1. 函数对象与实例对 ...

  6. 回调地狱的多种解决方式

    什么是回调地狱     异步的JavaScript程序,或者说使用了回调函数的JavaScript程序,很难地去直观顺畅地阅读,大量的代码以下面这种方式结束.简单说,就是函数作为参数层层嵌套.代码以此 ...

  7. 链式调用和解决回调地狱的终极解决方法async,await

    promise链式调用 **then 是成功回调,只要在then后边return一个promise就可以继续then**<script type="text/javascript&qu ...

  8. 避免回调地狱的解决方案 async/await:用同步的方式去写异步代码

    文章目录 前言 一.引入异步编程 二.常见处理异步编程的几种方式 1.Generator函数 2.Promise函数 3.async/await 总结 前言 这篇文章主要给大家分享一下,自己关于异步编 ...

  9. 回调地狱,解决回调地狱,回调地狱的终极解决方案

    回调地狱示例 使用promise的链式调用解决回调地狱 async/await:回调地狱的终极解决方案

最新文章

  1. FineUI小技巧(4)关闭窗体那些事
  2. codeforces425C
  3. 单元测试以及dagger的使用
  4. oracle 11g禁用和强制direct path read
  5. 马斯克获评最鼓舞人心科技领导者,马云排名第5
  6. 海龟交易法则07_如何衡量风险
  7. html 设置font size,css font-size属性说明
  8. hdu-5723 Abandoned country(最小生成树+期望)
  9. c++和QT实现俄罗斯方块,使用GraphicsView。
  10. 电信网关-天翼网关-GPON-HS8145C设置桥接路由拨号认证
  11. 神经网络可以计算任何函数的可视化证明
  12. 台式计算机配置清单4500,4500组装电脑配置清单
  13. 迅雷9去右侧浏览器补丁
  14. C语言模拟回合制游戏 源码
  15. Linux中级(七)SAMBA文件服务器
  16. java采用降低图片分辨率大小来压缩图片大小
  17. ssm和springboot的区别
  18. 聊聊职场 - 个人发展
  19. 分布式网络游戏百万人同时在线服务器架构实现(思想)
  20. 等保2.0.整体测评结果分析

热门文章

  1. 易语言注册机sign加密解决方法
  2. [AHK]输入法状态提示,中文状态提示“中”,英文状态提示“EN”
  3. 投食Reactelectron脚手架
  4. Java中实现在线语音识别(科大讯飞免费的SKD)、SDK下载和IDEA项目搭建、成功运行【完整代码】
  5. Nonlinear Component Analysis as a Kernel Eigenvalue Problem
  6. 江西地区媒体邀约资源现场官方直播推荐
  7. 【论文笔记】Forensic Similarity for Digital Images
  8. 春季学习报告 4.12
  9. 最新最全论文合集——3D重建
  10. 8个角度分析:CRM功能