zoukankan      html  css  js  c++  java
  • Promise

    Promise和async/await

    Promise/A+规范

    早期的期约机制在jQuery和Dojo中是以DeferredAPI的形式出现的。到了2010年,CommonJS项目实现的Promises/A规范日益流行起来。Q和Bluebird等第三方JavaScript期约库也越来越得到社区认可,虽然这些库的实现多少都有些不同。为弥合现有实现之间的差异2012年Promises/A+组织分叉(fork)了CommonJS的Promises/A建议,并以相同的名字制定了Promises/A+规范。这个规范最终成为了ECMAScript6规范实现的范本。ECMAScript6增加了对Promises/A+规范的完善支持,即Promise类型。一经推出,Promise就大受欢迎,成为了主导性的异步编程机制。所有现代浏览器都支持ES6期约,很多其他浏览器API(如fetch()和BatteryStatusAPI)也以期约为基础。

    期约基础

    ECMAScript6新增的引用类型Promise,可以通过new操作符来实例化。

    期约状态机

    期约是一个有状态的对象,可能处于如下3种状态之一:

    • 待定(pending)
    • 兑现(fulfilled,有时候也称为“解决”,resolved)
    • 拒绝(rejected)

    通过执行函数控制期约状态

    由于期约的状态是私有的,所以只能在内部进行操作。内部操作在期约的执行器函数中完成。执行器函数主要有两项职责:初始化期约的异步行为和控制状态的最终转换。其中,控制期约状态的转换是通过调用它的两个函数参数实现的。这两个函数参数通常都命名为resolve()和reject()。调用resolve()会把状态切换为兑现,调用reject()会把状态切换为拒绝。另外,调用reject()也会抛出错误。

    Promise.resolve()

    期约并非一开始就必须处于待定状态,然后通过执行器函数才能转换为落定状态。通过调用Promise.resolve()静态方法,可以实例化一个解决的期约。

    • 这个解决的期约的值对应着传给Promise.resolve()的第一个参数。使用这个静态方法,实际上可以把任何值都转换为一个期约。
    • 对这个静态方法而言,如果传入的参数本身是一个期约,那它的行为就类似于一个空包装。因此,Promise.resolve()可以说是一个幂等方法。
    • 这个静态方法能够包装任何非期约值,包括错误对象,并将其转换为解决的期约。

    Promise.reject()

    与Promise.resolve()类似,Promise.reject()会实例化一个拒绝的期约并抛出一个异步错误(这个错误不能通过try/catch捕获,而只能通过拒绝处理程序捕获)。

    • 这个拒绝的期约的理由就是传给Promise.reject()的第一个参数。这个参数也会传给后续的拒绝处理程序。
    • 关键在于,Promise.reject()并没有照搬Promise.resolve()的幂等逻辑。如果给它传一个期约对象,则这个期约会成为它返回的拒绝期约的理由。

    期约的实例方法

    期约实例的方法是连接外部同步代码与内部异步代码之间的桥梁。这些方法可以访问异步操作返回的数据,处理期约成功和失败的结果,连续对期约求值,或者添加只有期约进入终止状态时才会执行的代码。

    实现Thenable接口

    在ECMAScript暴露的异步结构中,任何对象都有一个then()方法。这个方法被认为实现了Thenable接口。ECMAScript的Promise类型实现了Thenable接口。这个简化的接口跟TypeScript或其他包中的接口或类型定义不同,它们都设定了Thenable接口更具体的形式。

    Promise.prototype.then()

    Promise.prototype.then()是为期约实例添加处理程序的主要方法。这个then()方法接收最多两个参数:onResolved处理程序和onRejected处理程序。这两个参数都是可选的,如果提供的话,则会在期约分别进入“兑现”和“拒绝”状态时执行。

    • 因为期约只能转换为最终状态一次,所以这两个操作一定是互斥的。
    • 如前所述,两个处理程序参数都是可选的。而且,传给then()的任何非函数类型的参数都会被静默忽略。如果想只提供onRejected参数,那就要在onResolved参数的位置上传入undefined。这样有助于避免在内存中创建多余的对象,对期待函数参数的类型系统也是一个交代。
    • Promise.prototype.then()方法返回一个新的期约实例,这个新期约实例基于onResovled处理程序的返回值构建。换句话说,该处理程序的返回值会通过Promise.resolve()包装来生成新期约。如果没有提供这个处理程序,则Promise.resolve()就会包装上一个期约解决之后的值。如果没有显式的返回语句,则Promise.resolve()会包装默认的返回值undefined。
    • 如果有显式的返回值,则Promise.resolve()会包装这个值。
    • 抛出异常会返回拒绝的期约,返回错误值不会触发拒绝行为,而会把错误对象包装在一个解决的期约中。
    • onRejected处理程序也与之类似:onRejected处理程序返回的值也会被Promise.resolve()包装。乍一看这可能有点违反直觉,但是想一想,onRejected处理程序的任务不就是捕获异步错误吗?因此,拒绝处理程序在捕获错误后不抛出异常是符合期约的行为,应该返回一个解决期约。

    Promise.prototype.catch()

    Promise.prototype.catch()方法用于给期约添加拒绝处理程序。这个方法只接收一个参数:onRejected处理程序。事实上,这个方法就是一个语法糖,调用它就相当于调用Promise.prototype.then(null,onRejected)。

    Promise.prototype.finally()

    Promise.prototype.finally()方法用于给期约添加onFinally处理程序,这个处理程序在期约转换为解决或拒绝状态时都会执行。这个方法可以避免onResolved和onRejected处理程序中出现冗余代码。但onFinally处理程序没有办法知道期约的状态是解决还是拒绝,所以这个方法主要用于添加清理代码。

    • Promise.prototype.finally()方法返回一个新的期约实例。
    • 这个新期约实例不同于then()或catch()方式返回的实例。因为onFinally被设计为一个状态无关的方法,所以在大多数情况下它将表现为父期约的传递。对于已解决状态和被拒绝状态都是如此。
    • 如果返回的是一个待定的期约,或者onFinally处理程序抛出了错误(显式抛出或返回了一个拒绝期约),则会返回相应的期约(待定或拒绝),如下所示。
    • 返回待定期约的情形并不常见,这是因为只要期约一解决,新期约仍然会原样后传初始的期约。

    非重入期约方法

    当期约进入落定状态时,与该状态相关的处理程序仅仅会被排期,而非立即执行。跟在添加这个处理程序的代码之后的同步代码一定会在处理程序之前先执行。即使期约一开始就是与附加处理程序关联的状态,执行顺序也是这样的。这个特性由JavaScript运行时保证,被称为“非重入”(non-reentrancy)特性。

    Promise.all()和Promise.race()

    Promise 类提供两个将多个期约实例组合成一个期约的静态方法:Promise.all()和Promise.race()。而合成后期约的行为取决于内部期约的行为。

    Promise.all()

    Promise.all()静态方法创建的期约会在一组期约全部解决之后再解决。这个静态方法接收一个可迭代对象,返回一个新期约。

    • 合成的期约只会在每个包含的期约都解决之后才解决。如果至少有一个包含的期约待定,则合成的期约也会待定。如果有一个包含的期约拒绝,则合成的期约也会拒绝。
    • 如果所有期约都成功解决,则合成期约的解决值就是所有包含期约解决值的数组,按照迭代器顺序。
    • 如果有期约拒绝,则第一个拒绝的期约会将自己的理由作为合成期约的拒绝理由。之后再拒绝的期约不会影响最终期约的拒绝理由。不过,这并不影响所有包含期约正常的拒绝操作。合成的期约会静默处理所有包含期约的拒绝操作。

    Promise.race()

    Promise.race()静态方法返回一个包装期约,是一组集合中最先解决或拒绝的期约的镜像。这个方法接收一个可迭代对象,返回一个新期约。

  • 相关阅读:
    Ubuntu下ClickHouse安装
    redis.conf配置详解(转)
    php使用sftp上传文件
    ubuntu下安装nginx1.11.10
    cookie和session的区别
    linux下Redis主从复制
    linux-ubuntu 安装配置Redis
    php的常量
    Ubuntu防火墙配置
    技术资料
  • 原文地址:https://www.cnblogs.com/1328497946TS/p/15364034.html
Copyright © 2011-2022 走看看