Warcry mpi
  1. 1 Warcry mpi
  2. 2 Life Will Change Lyn
  3. 3 Flower Of Life 发热巫女
  4. 4 Quiet Storm Lyn
  5. 5 One Last You Jen Bird
  6. 6 Time Bomb Veela
  7. 7 かかってこいよ NakamuraEmi
  8. 8 The Night We Stood Lyn
  9. 9 Libertus Chen-U
  10. 10 Last Surprise Lyn
  11. 11 Hypocrite Nush
2017-01-20 12:17:09

异步编程——Promise

之前我们说到,当通过回调函数执行多步异步操作时,会创造难以理解和调试的代码,而且也缺乏控制异步操作时机的手段。比如想让两个异步操作同时运行,或者同时启动多个异步操作只采用某个结果,都很难做到。在这些情况下,通过使用ES6的新特性——Promise将能大幅度改善这种情况。


什么是Promise?

我们都知道,之前在构建异步事件处理函数时,都是通过传入回调函数的手段将事件和方法耦合在一起在实现的。这也是多个异步操作串联时难以操作的原因。而Promise就相当于事件和方法的中转站,将事件和方法解耦,从而使整个异步过程变得清晰。

Promise就是为异步事件的结果准备的占位符,该占位符承接异步事件的状态,根据不同状态来开启针对异步事件的方法的执行。Promise通过它的生命周期来承接异步事件的状态。

Promise的生命周期

Promise内部存在[[PromiseState]]属性,该属性有'pending','fulfilled','rejected'来反映异步事件的状态。

  • pending(挂起态): 异步事件尚未结束。
  • fulfilled(已完成): 异步事件已成功结束。
  • rejected(已拒绝): 异步事件未成功结束,可能发生了一个错误。

该属性会随着异步事件的发生流程而改变,我们通过then()方法监听该属性,来开启针对不同流程所执行的方法。Promise初始为挂起态,只可以单向转换为已完成或已拒绝。无论转化为哪种状态,Promise都可以称为已决态。

至此我们就实现了一个异步事件处理流程,也完成了事件与方法的分离。

Promise的创建

Promise通过Promise构造器来创建。该构造器接受单个参数:一个被称为执行器(executor)的函数,该函数包含初始化Promise的代码,并且被传递两个名为resolve()与reject()的函数作为参数。reslove()在执行器结束后被调用,表示进入fulfilled状态。而当执行器操作失败时,reject()被调用,表示进入rejected状态。我们通过then()方法监听Promise的状态,第一个参数为fulfilled状态调用的函数,第二个参数为rejected状态调用的函数。

下面以一个读取文件的异步操作例子来解释整个流程:

let fs = require("fs");

let promise = new Promise(function(resolve,reject){
    //触发执行器异步事件
    fs.readFile(filename,{encoding: "utf-8"},function(err,contents){
        if(err){
        //执行器操作失败,进入rejected状态
            reject(err);
            return 
        }
        //执行器操作成功,进入fulfilled状态
        resolve(contents);
    });   
});

//分别监听两个状态并输出执行器返回值
promise.then(function(contents){
    console.log(contents);
},function(err){
    console.error(err.message);
});

在Promise中执行器会立刻执行,resolve()或reject()的完成会作为异步事件操作结束的标志,转换Promise状态并添加进事件循环队列,以便then函数进行后续监听。

then()方法在所有Promise上都存在,传递给then的两个参数都可选,因此可以进行各种形式与数量的监听与拒绝函数。

当只监听rejected状态时,可以使用更简单的catch()方法。

已决的Promise的创建

有时候我们可能并不需要创建复杂的异步操作,只想让Promise代表一个已知的值。那么我们可以用以下两种方法创建已决的Promise。

Promise.resolve()

该方法接受单个参数并返回一个fulfilled状态的Promise。我们可以通过then方法的第一个函数参数接收该值并处理。

Promise.reject()

该方法接受单个参数并返回一个rejected状态的Promise。我们可以通过then方法的第二个函数参数接收该值并处理。

Promise的串联操作

目前我们了解了单个Promise的处理流程,而只对一个异步事件进行处理的话用回调函数其实就足够了。Promise拥有同时处理多个异步事件串联的能力,这正是回调函数难以做到的。其关键在于then()或catch()方法调用时实际上创建并返回了另一个未决的Promise。当前一个Promise已决时,才能进行后续的决议。

之前的流程我们可以看出,传递给执行器中的resolve()的参数会被传递给Promise的then()对应的函数参数。而当Promise串联时,对应函数参数的返回值也会继续向下传递给Promise对象的then()对应函数参数,返回值也可以是一个新建的Promise对象。reject()函数也是同理。

多个Promise的响应

有时我们可能想同时监视多个异步操作,以便根据总体情况决定接下来的行动。ES6提供了两个方法:

Promise.all()

该方法接受单个可迭代对象作为参数并返回一个Promise。这个参数元素都是Promise,只有在它们都被决议后,返回的Promise才会被决议。如果所有参数Promise都是fulfilled状态,则返回的Promise也是fulfilled状态并接收一个包含每个决议值的数组。若任意参数Promise被拒绝,那么返回的Promise会立刻被拒绝。

Promise.race()

该方法接受参数同上,但返回的Promise状态如同该方法名,与最快转化为已决态的参数Promise相同。

-- EOF --

添加在分类「 前端开发 」下,并被添加 「JavaScript」「Node.js」 标签。