ES6 - Promise

177 阅读4分钟

Promise是一种异步编程的比较优雅的解决方案

可以避免回调地狱

回调地狱:回调层层嵌套,函数作为参数,可读性和可维护性差

Promise可以理解为一个容器,里面保存着未来才会结束的事件

Promise对象的特点

  1. 对象的状态不受外界影响

    Promise对象代表一个异步操作,其有三种状态:Pending、Fulfilled和Rejected。 且转变关系只有

    Pending -> Fulfilled
    Pending -> Rejected
    
  2. 一旦状态改变就不会再变,并且状态在任何时候都可以获得

    Promise对象的状态一旦变为Fulfilled或Rejected会一直保持结果,称为"已定型(Resolved)"

    与JS中的事件不同,事件一旦错过,就不可再监听到

Promise - Hello world!

var promise = new Promise(function(resolve, reject) {
    // some code
    const value = someAsyncFunctions();
    // some code
    if (/* 异步操作成功 */) {
        resolve('I got the value of some async functions', value);
    } else {
        reject('Oh, some errors occured...')
    }
});

以上通过一个Promise构造函数构造了一个Promise对象promise, Promise构造函数接受一个函数作为参数,该函数的两个参数resolverejectJavascript引擎实现的,不用关注实现细节

resolve是Promise内部回调执行成功后的处理函数,会将Promise对象的状态从Pending变为Resolved

reject是Promise内部回调执行成功后的处理函数,会将Promise对象的状态从Pending变为Rejected

console.log(promise)就会看到被Promise住的异步操作的结果:I got the value of some async functionsOh, some errors occured...

Promise.then() || Promise.prototype.then()

官方解释:定义在原型对象Promise.prototype上的,作用是为Promise示例添加状态改变时的回调函数

通俗理解:Promise执行完了该干点啥,then()中的操作很可能是依赖于被Promise的异步操作的结果。

注意: then方法的第一个参数Resolved状态的回调函数,第二个参数(可选)是Rejected状态的回调函数。如下:

var promise = new Promise((resolve, reject) => {
    // some code
    const value = someAsyncFunctions();
    // some code
    if (/* 异步操作成功 */) {
        resolve('I got the value of some async functions', value);
    } else {
        reject('Oh, some errors occured...')
    }
}).then((success) => {
    console.log('The Promise succeed, and it returns ', success) // 此处的success值即为第一个Promise的Resolved时的返回值
}, (fail) => {
    console.log('The Promise failed, and it returns ', fail) // 此处的fail值同理
})

then方法返回的是一个Promise实例。 .then()可一直写下去,此即为链式调用。

Promise.catch() || Promise.prototype.catch() 本身不新鲜

只是Promise.prototype.then(null, rejection)的别名

写法稍有不同:

// 如果只是then(null, rejection)的话,错误处理函数即为rejection,如下:

new Promise((resolve, reject) => {
    // some code
}).then(null, (rejection) => {
    // do something when error occurs
})
// 这时候的rejection方法只是then方法的第二个参数

// 如果使用Promise.catch(),则catch方法是跟then方法同级的存在
new Promise((resolve, reject) => {
    // some code
}).then((success) => {
    // do something when Promise is success
}).catch((error) => {
    console.log('Error! ', error);
})
// 注意: 这里catch能catch第一个Promise中发生的错误,也能catch then方法中发生的错误

// catch能捕获之前所有的Promise对象产生的错误,因为Promise对象的错误有“冒泡”的属性,会一直向后传递,直到被捕获

// 下面几种写法是等价的:

1.
var promise = new Promise((res, rej) => {
    throw new Error('test');
});
promise.catch((error) => {
    console.log('error'); // Error: test
});

2.
var promise = new Promise((res, rej) => {
    try {
        throw new Error('test');
    } catch(err) {
        reject(e);
    }
});
promise.catch((error) => {
    console.log(error);
});

3.
var promise = new Promise((res, rej) => {
    reject(new Error('test'));
});
promise.catch((error) => {
    console.log(error);
});
// reject方法作用就是抛出错误了吧。。。

一般来说,使用catch方法优于使用then方法的第二个参数捕获错误,因为catch可以捕获then方法中的错误

Promise.all() 将多个Promise对象包装成一个新的Promise实例

var p = Promise.all(p1, p2, p3)

p的状态由p1, p2, p3决定

  • 只有p1, p2, p3的状态都变成Fullfilled,p的状态才变成Fullfilled,p1 p2 p3的返回值组成一个数组,传给p的回调函数
  • p1, p2, p3中有一个被Rejected,p的状态就变成Rejected

只有p1, p2, p3都变成Fullfilled或有一个变成Rejected之后,才开始执行p

Promise.race() 跟Promise.all()差不多,不同的是只要p1, p2, p3中有一个状态变成Fullfilled,p的状态就跟着改变,最先改变的Promise实例的返回值传给p的回调函数