资讯专栏INFORMATION COLUMN

Promise in ECMAScript | 前端技术探索

SillyMonkey / 1042人阅读

摘要:而纳入规范的也是建立在基础上的。继续阅读的相关解释语法其中函数拥有两个参数和。可以看到,在语法上看,还是有点像回调函数那种形式的,囧。完成操作已经成功执行完毕。消费,即对的所代表的值进行一系列的处理。

文 | Leigh,UPYUN 已获得授权
原文链接:http://t.cn/R403hc4

在 JavaScript 这么多年发展中,尤其在前端领域框架层出不穷,解决方案也琳琅满目,Promise 这个思想也逐渐从一个框架层面的实现变成了 ES 的规范,并且越来越多的新 API 都在以 Promise 为基础制定。是时候来看看这个怪物了!

什么是 Promise

在 JavaScript 尤其是前端开发领域,Promise 已经存在不少时日了,有一些曾经广受好评的第三方库,例如 Q,when,Bluebird,RSVP,基本都曾名噪一时,尽管实现方式/API 不一样,但它们大多都遵循着 Promises/A+ 这个‘事实规范’。而纳入 ES 规范的 Promise API 也是建立在 Promises/A+ 基础上的。

要注意的是,jQuery 虽然有一个类似 Promise 的 API,但是它的 Promise 实际上是被称作为 Deferred 对象的一个东西,它跟 Promises/A+ 的规范是不太兼容。

Promise 主要用来解决 JS 开发中的异步问题,而对异步的处理,社区中也有着不少的解决方案,最多的就是回调这种形式,比如,在 Node.js 中:

这种书写上的约定,很容易解决对异步操作的处理,但缺陷是,这样的写法,我们没发直接在异步函数中进行 return 和 throw 操作,只能局限于回调的形式中,并且很容易引起回调金字塔的情况。Promise 则对异步处理和处理方法都做了规范和抽象,还给了开发者在异步代码中使用 return 和 throw 的能力。而这也是 Promise 存在的真正意义。继续阅读 domenic 的相关解释

语法

其中 executor 函数拥有两个参数 resolve 和 reject。resolve 用于肯定 Promise,reject 用于否定它,我们可以在相关的操作结束后来执行这两个函数。

可以看到,在语法上看,Promise 还是有点像回调函数那种形式的,囧。不过,和回调函数相比,它的主要不同点在于:

1、每一个 Promise 都保证能让我们收到一个值,Promise 便是这个值的代理,而我们无需关心它被创建的时间点,我们更可以在任意时刻注册我们的结果处理函数,即使这个 Promise 已经完成(resolved)了(这时候,所注册的处理函数会被立即执行)。

2、每一个 Promise 都只会被成功或失败一次,并且这个状态不会被改变。

一个 Promise,会拥有以下几个状态之一:

1、pending(等待):操作正在执行中。
2、fulfilled(完成):操作已经成功执行完毕。
3、reject(失败):操作执行失败。

某些文章中可能会说到 settled 这个词,settled 代表 Promise 不是 pending 的状态,即:要么是 fulfilled,要么是 reject。但他本身并不是一个状态,只是为了说的时候方便。详见 domenic: States and Fates

Promise 的状态变化图如下:

使用 Promise

创建

创建一个 Promise,直接的方法是直接 new Promise 创建一个,即上文中语法中所述一样。其接受一个 executor 函数作为参数传递,Promise 在 executor 函数中提供了 resolve 和 reject 两个函数供开发者根据实际结果来调用。

在 Promise 对象上,还有 Promise.all(iterable), Promise.race(iterable), Promise.reject(reason), Promise.resolve(value) 四个方法,这些方法也会返回 Promise 对象,因此,我们也可以通过这些方法来直接创建一个方法,例如 var p = Promise.resolve("I am a Promise!");

消费

Promise 一旦创建,我们就可以把它当做一个值来传递,因为 Promise 就是对一个未来会得到的值的代表。因此,你可以将它从函数中返回(return),也可以当做参数来传递到需要的地方,就像传递一个普通的值一样。

消费 Promise,即对 Promise 的所代表的值进行一系列的处理。这里,我们可以使用 .then() 方法。

.then() 方法可以接受两个函数作为参数,第一个参数的函数会在 Promise 完成(fulfilled)的时候被调用,而第二个参数的函数则在 Promise 失败 (rejected)的时候调用。这两个参数都是可以被省略的:

每个 Promise 实例还有一个 .catch() 方法,主要用于对错误的处理,对于 .catch() 的方法理解,其实很简单,它就相当于 .then() 省略第一个参数:

上述两种形式对错误的处理是等效的,当 Promise 失败的时候,两段代码的执行结果一样。不过,一般情况下,更加推荐使用 .catch() 方法来处理错误,因为 catch 本身名字更加直接易懂,并且,在链式调用 Promise 的时候,只需要在调用链最末端使用一个 .catch() 即可。

在 Promise 中,当直接 throw 一个异常的时候,将会使该 Promise 置为 rejected 状态,这里需要注意的是,在 Promise 链中抛出异常,仅仅会将抛出异常所在的 Promise 置为 rejected,而不会影响原始的 Promise,比如:

处理多个异步操作
Promise.all()

在很多时候,我们都希望多个异步操作能够并行,但很多情况下,我们又希望能在这多个异步操作全部都完成后再对结果进行处理,这个时候,我们就会用到 Promise.all(),这个方法接受一个 Promise 数组作为参数,且会在所有 Promise 完成后执行一次回调 .then(),在这里,所有数组中的 Promise 都是并行方式执行的,如下:

注意:只要一旦有一个 promise 失败,.catch() 中的逻辑就会被执行。

Promise.all() 在一些大型 web app 中,将会很有用,因为大多良好的 API 设计都是以数据维度划分,产品的某一个功能,可能会涉及到多个 API 的数据联动,这时候,使用 Promise.all() 即可方便的解决。

Promise.race()

Promise.race() 它同样接受一个 Promise 数组作为参数,顾名思义,"race" 即比赛,想象一下,在平时百米竞赛时候,一旦有人率先冲过终点,那变产生了一个冠军,Promise.race() 即是在数组中的任意一个 Promise 完成后,便会触发 .then() 的逻辑,当然,这里数组中的 Promise 也是并行的:

Promise.race() 的经典使用场景是某个服务有多个互备的形式,而我们需要尽快的拿到结果。

Series

并行很容易,但是 Promise 并没有一个直接使用的串行的方法,当然,结合一些函数式编程的方法,我们可以很简单的自行实现一下:

总结

Promise 最近变得越来越火,无论前端领域,例如:Fetch API,Battery API,以及还未完成的 ServiceWorker API 等,甚至在 Node.js 社区中,人气很高的 co,以及 koa 新版本都将 thunk 的形式改为了 Promise,在实际生产中投入使用,阻力也不会太大。

连接

ES 规范
MDN 文档
Can I Use 兼容性参考
es6-promise polyfill

欢迎关注 UPYUN 微信公众号( ID : upaiyun ),我们每周都会分享高质量的原创技术文章。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78491.html

相关文章

  • FCC 成都社区·前端周刊 第 7 期

    摘要:详情发布于月号发布了版本,除了性能改进修复外,首次添加了贡献者的安装脚本。详情中的应用在中悄悄增加了对渐进式应用这一系列新技术的基本支持,这意味着现在可以在没有批准的情况下在上安装应用程序,不过会有一些限制。 01. ES2016, 2017, 2018 中的新特性 文章介绍了 18 个 ECMAScript 2016,2017 和 2018 中新增加的特性,这些特性已被加入到 TC3...

    source 评论0 收藏0
  • FCC 成都社区·前端周刊 第 7 期

    摘要:详情发布于月号发布了版本,除了性能改进修复外,首次添加了贡献者的安装脚本。详情中的应用在中悄悄增加了对渐进式应用这一系列新技术的基本支持,这意味着现在可以在没有批准的情况下在上安装应用程序,不过会有一些限制。 01. ES2016, 2017, 2018 中的新特性 文章介绍了 18 个 ECMAScript 2016,2017 和 2018 中新增加的特性,这些特性已被加入到 TC3...

    NikoManiac 评论0 收藏0
  • FCC 成都社区·前端周刊 第 7 期

    摘要:详情发布于月号发布了版本,除了性能改进修复外,首次添加了贡献者的安装脚本。详情中的应用在中悄悄增加了对渐进式应用这一系列新技术的基本支持,这意味着现在可以在没有批准的情况下在上安装应用程序,不过会有一些限制。 01. ES2016, 2017, 2018 中的新特性 文章介绍了 18 个 ECMAScript 2016,2017 和 2018 中新增加的特性,这些特性已被加入到 TC3...

    hiYoHoo 评论0 收藏0
  • 前端相关汇总

    摘要:简介前端发展迅速,开发者富有的创造力不断的给前端生态注入新生命,各种库框架工程化构建工具层出不穷,眼花缭乱,不盲目追求前沿技术,学习框架和库在满足自己开发需求的基础上,然后最好可以对源码进行调研,了解和深入实现原理,从中可以获得更多的收获随 showImg(https://segmentfault.com/img/remote/1460000016784101?w=936&h=397)...

    BenCHou 评论0 收藏0
  • 校招社招必备核心前端面试问题与详细解答

    摘要:本文总结了前端老司机经常问题的一些问题并结合个人总结给出了比较详尽的答案。网易阿里腾讯校招社招必备知识点。此外还有网络线程,定时器任务线程,文件系统处理线程等等。线程核心是引擎。主线程和工作线程之间的通知机制叫做事件循环。 showImg(https://segmentfault.com/img/bVbu4aB?w=300&h=208); 本文总结了前端老司机经常问题的一些问题并结合个...

    jonh_felix 评论0 收藏0

发表评论

0条评论

SillyMonkey

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<