近期学习的ES6,关于Promise的部分。

Promise 的基本格式

var promise = getAsyncPromise('fileA.txt');
promise.then(function(result) {
    // 获取文件内容成功时的处理
}).catch(function(error) {
    // 获取文件内容失败时的处理
})


API

  • 三种类型的API

  • Constructor 构造函数 Promise

var promise = new Promise(function(resolve, reject) {
    // 异步处理
    // 处理结束后,调用resolve或 reject
})
  • Instance Method 实例方法 then catch

    • 对于通过new 生成的promise对象为了设置其值resolve/reject 时调用的回调函数,可以使用promise.then()实例方法。

    • promise.then(onFulfilled, onRejected),成功时onFulfilled会被调用,失败时onRejected会被调用

    • onFulfilledonRejected都是可选参数

  • Static Method 静态方法

Promise.all()
Promise.race()
Promise.resovle()
Promise.reject()


Promise的状态

  • 三种状态

    • has-resolution = Fulfilled

    • has-rejection = Rejected

    • unresolved = Pending

  • 没有公开访问状态的api方法

  • 从Pending转换为FulfilledRejected之后,promise的状态不会再改变

  • FulfilledRejected这两种状态是不可变

  • 当promise的对象状态发生变化时,用.then来定义只会被调用一次的函数


编写promise对象的处理方法

  • 被resolve后的处理,可以在 .then 方法中传入想要调用的函数

  • 被reject后的处理,可以在 .then 的第二个参数或者是在 .catch 方法中设置想要调用的函数

  • 一般说来,使用 .catch 来将resolve和reject处理分开来写是比较推荐的做法


Promise.resolve

  • 静态方法Promise.resolve(value)可以认为是 new Promise() 方法的快捷方式

  • 比如 Promise.resolve(42); 可以认为是以下代码的语法糖

new Promise(function(resolve){
    resolve(42);
});
  • 方法 Promise.resolve(value); 的返回值也是一个promise对象

  • Promise.resolve 方法另一个作用就是将 thenable 对象转换为promise对象。thenable指的是一个具有 .then 方法的对象。

  • 除了在编写使用Promise的类库等软件时需要对Thenable有所了解之外,通常作为end-user使用的时候,我们可能不会用到此功能。


Promise.reject

  • Promise.reject(error) 是和 Promise.resolve(value) 类似的静态方法

  • 比如 Promise.reject(new Error("出错了")) 就是下面代码的语法糖形式

new Promise(function(resolve,reject){
    reject(new Error("出错了"));
});


Promise只能进行异步操作?

  • Promise在规范上规定 Promise 只能使用异步调用方式

  • 即使在调用 promise.then 注册回调函数的时候promise对象已经是确定的状态,Promise也会以异步的方式调用该回调函数

  • 关于这个问题,在 Effective JavaScript第67项 不要对异步回调函数进行同步调用 中也有详细介绍。

    • 绝对不能对异步回调函数(即使在数据已经就绪)进行同步调用。

    • 如果对异步回调函数进行同步调用的话,处理顺序可能会与预期不符,可能带来意料之外的后果。

    • 对异步回调函数进行同步调用,还可能导致栈溢出或异常处理错乱等问题。

    • 如果想在将来某时刻调用异步回调函数的话,可以使用 setTimeout 等异步API。

  • 由于Promise保证了每次调用都是以异步方式进行的,所以我们在实际编码中不需要调用 setTimeout 来自己实现异步调用


Promise#then

  • promise可以写成方法链的形式
aPromise.then(function taskA(value){
    // task A
}).then(function taskB(vaue){
    // task B
}).catch(function onRejected(error){
    console.log(error);
});


promise chain 中如何传递参数

  • Task A 中 return 的返回值,会在 Task B 执行时传给它
function doubleUp(value) {
    return value * 2;
}
function increment(value) {
    return value + 1;
}
function output(value) {
    console.log(value);// => (1 + 1) * 2
}

var promise = Promise.resolve(1);
promise
.then(increment)
.then(doubleUp)
.then(output)
.catch(function(error){
    // promise chain中出现异常的时候会被调用
    console.error(error);
});
  • Promise#then 不仅仅是注册一个回调函数那么简单,它还会将回调函数的返回值进行变换,创建并返回一个promise对象。


每次调用then都会返回一个新创建的promise对象

  • then 的错误使用方法
function badAsyncCall() {
    var promise = Promise.resolve();
    promise.then(function() {
    // 任意处理
    return newVar;
});
    return promise;
}
  • 这种写法有很多问题,首先在 promise.then 中产生的异常不会被外部捕获,此外,也不能得到 then 的返回值,即使其有返回值。
    • 正确的写法
function anAsyncCall() {
    var promise = Promise.resolve();
    return promise.then(function() {
        // 任意处理
        return newVar;
    });
}


promise.all

  • promise.all 接收一个promise对象的数组作为参数,当这个数组里的所有promise对象全部变为resolve或reject状态的时候,它才会调用.then方法。

  • 传递给Promise.all的promise并不是一个个的顺序执行,而是同时开始、并行执行的。

  • 每个promise的结果(resolve或reject时传递的参数值),和传递给Promise.all的promise数组的顺序是一致的。


promise.race

  • promise.race使用方法和Promise.all一样,接收一个promise对象数组为参数。当数组里只要有一个promise对象进入FulFilled或者Rejected状态,就会继续进行后面的处理。

-当一个promise变为确定(FulFilled)状态后,并不会取消其他promise对象的执行。


then or catch

  • 使用promise.then(onFulfilled, onRejacted)的话,在onFulfilled中发生异常的话,在onRejected中是捕获不到这个异常的。

  • promise.then(onFulfilled).catch(onRejected)的情况下,then中产生的异常能在.catch中捕获

  • .then.catch在本质上是没有区别的,需要注意分场合使用。


来源:

JavaScript Promise迷你书(中文版)