深入理解ES6-11.Promise(1)

680 阅读3分钟

Promise的3个状态

Promise 中有一个 [[PromiseState]] 内部属性,用于表示 Promise 的三种状态:

  1. Pending 此时操作尚未完成,表示处于进行中的状态。
  2. Fulfilled 此时操作已经完成,表示处于操作成功中的状态。
  3. Rejected 此时操作已经完成,表示处于操作失败中的状态。

Promise 的状态改变只有两种情况,一旦操作完成不可逆:

  1. Pending ————> Fulfilled
  2. Pending ————> Rejected

它不会暴露在 Promise 对象上,所以不能以编程的方式检测出其状态,只有当 Promise 状态改变的时候,会触发特定的方法。

Promise的2个方法

then()

Promise 的状态改变的时候,也就是从 Pending 状态变成 Fulfilled 或者 Rejected 状态的时候,会调用 then() 方法。它接收两个可选参数:

  1. Promise 的状态变为 fullfilled 时调用的完成函数
  2. Promise 的状态变为 rejected 时调用的拒绝函数
promise.then(
  function(contents) {...},
  function(err) {...},
)

如果一个对象实现了上述的 then() 方法,就可以称为 thenable 对象,Promisethenable 对象的一个子集。

可以传入两个参数,表示完成函数和拒绝函数;也可以传入一个参数,表示完成函数;如果只想要拒绝函数,需要将第一个参数置为 null,这样使用有点奇怪,所以提供了一个专门处理操作失败的方法。

catch()

catch() 相当于只给其传入拒接处理程序的 then() 方法。

promise.catch(
  function(err) {...}
)

创建未完成的 Promise

Promise 构造函数

new Promise(executor) 构造函数创建新的 promise,接收一个执行器参数, 执行器在创建时会立即执行\color{#ff3030}{执行器在创建时会立即执行}。执行器又接收两个参数,resolve 函数和 reject 函数。执行器成功完成调用 resolve 函数,失败调用 reject 函数。

resolve 函数会将 Promise 的状态变成 fullfilledreject 函数会将 Promise 的状态变成 rejected

let i = 12;
let promise = new Promise(function(resolve,reject){
    if(i<10){ reject('i不能小于10'); return; }
    resolve(i);
});
console.log(promise);
promise.then((value) => {
  console.log(value)
}, (err) => {
  console.log(err)
})

这样使用创建出来的是一个 fullfilled 状态的 promise,所以会直接触发 then() 方法并执行完成函数。如果 i<10,会创建一个 rejected 状态的 promise,则会直接触发 then() 方法并执行失败函数。

未完成的 Promise

需要将 resolve 函数和 reject 函数放到回调函数中处理,也就是异步处理。

var fs = require("fs")

function readFile(filename) {
    return new Promise( (resolve, reject) => {
        fs.readFile(filename, {encoding: "utf8"}, (err, contents) => {
            // 回调函数,会扔到异步任务队列中
            if (err) { reject(err); return; }
            resolve(contents);
        });
    });
}

let promise = readFile("../example1.txt");
console.log(promise);    // pending状态

promise.then(
    (contents) => {        
        console.log(contents);
        console.log(promise);    //fulfilled状态
    },
    (err) => {            
        console.error(err.message);
        console.log(promise);     //rejected状态
    });

创建已完成的 Promise

创建一个未完成的 Promise,最好使用 Promise 构造函数。但是使用构造函数创建一个已完成的 Promise,就想上两个例子,就显得没有什么意义。

Promise.resolve()

只接收一个参数:

  1. 参数为基础类型或普通对象,返回 fullfilled 状态的 Promise
  2. 参数为 Promise,直接返回传入的 Promise
  3. 参数为 Thenable 对象,会将这个 Thenable 对象转换为 Promise,并执行Thenable 对象的 then() 方法。
var fs = require("fs")

function readFile(filename) {
    return new Promise((resolve, reject) => {
        fs.readFile(filename, {encoding: "utf8"}, (err, contents) => {
            if (err) { reject(err);return; }
            resolve(contents);
        });
    });
}

//1.参数为非thenable对象或非对象或不传参,返回fulfilled状态的promise
let promise = Promise.resolve();
let promise1 = Promise.resolve(42);

//2.参数为promise实例,原封不动的返回传入的promise
let pending = readFile("../example.txt");   // pending状态
let promiseP1 = Promise.resolve(pending);   

//3.参数为thenable实例,返回fulfilled状态的promise
let thenable = {
    then: function (resolve, reject) {
        resolve(42);
    }
};
let p1 = Promise.resolve(thenable);

Promise.reject()

只接收一个参数,参数为基础类型或普通对象,返回 rejected 状态的 Promise。其他情况和 Promise.resolve() 一致。

执行器错误

如果在执行器中抛出一个错误,其实默认内部会使用 try-catch,捕获到错误后执行 reject() 方法。

let promise = new Promise(function(resolve,reject){
    throw new Error('Explosion!')
});
// 相当于
let promise = new Promise(function(resolve,reject){
    try {
      throw new Error('Explosion!')
    } catch (ex) {
      reject(ex)
    }
});