JS 中的 Promise

1,514 阅读4分钟

Promise 是异步编程的解决方案,它可以很方便的处理异步事件。一个 Promise 实例包含一个异步操作,这项异步操作只有三种状态,pending 初始状态,既不是成功,也不是失败状态,Resolved 成功完成,Rejected 异步操作失败。

Promise 的状态不受外界影响而且一旦状态改变,就不会再改变。

创建 Promise

要创建 Promise 实例要用到 Promise 类,它接受一个函数作为参数,函数接受两个参数,这两个参数也是函数,一个是当异步成功执行时需要调用的函数,一个是失败时调用的函数。

创建 Promise 实例的参数函数,将会立即执行。

function getData(url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", url);
        xhr.onload = () => resolve(xhr.responseText); 
        // 将状态变为 Resolved 并传入获取到的数据
        xhr.onerror = () => reject(xhr.statusText);
        // 将状态变为 Rejected 并传入错误信息
        xhr.send();
    })
}

//调用 getData 将返回一个 Promise 实例

Promise 的原型方法

Promise 一共有三个原型方法,then, catchfinally

then

then 方法接受两个函数参数,一个是成功时候执行,一个是失败时执行。

而且then方法将会返回一个新的 Promise 实例,这就代表可以进行链式操作。

立即调用resolvePromise,它then方法的参数函数会放到本次事件循环末尾。

let p1 = getData('http://www.a.cn')

let onFulfilled = data => console.log(data)
let onRejected = err => console.log(err)

p1.then(onFulfilled, onRejected)

// 当成功时将会调用第一个回调函数,并把 resolve 传入的参数再全部传入 onFulfilled 中

// 当成功时将会调用第二个回调函数,并把 resolve 传入的参数再全部传入 onRejected 中

let p2 = getData('http://www.a.cn')

p2.then(url => getData(url))
  .then(data => console.log(data)) // 链式操作
  
// ------------------

let p = new Promise(resolve => {
    console.log(1)
    resolve(3)
})

console.log(2)

setTimeout(() => console.log(4))
p.then(num => console.log(num))
// 打印顺序是 1 2 3 4

catch

catch 方法接受一个函数参数onRejectedcatch其实就是then的第二个参数。

catch方法一般放在最后面,前面then方法,将会冒泡到它这里。

catch 返回的还是一个 Promise 对象。不过catch捕获不了后面的then方法抛出的错误当然catch方法中也可以抛出错误。

let p3 = getData('http://a.com')

p3.then(data => console.log(data))
  .then(() => throw new Error('error')) // 抛出错误
  .then(() => console.log(1))
  .catch(err => console.log(err))
 
// catch 将会捕获上面的错误,而且第三个 then 方法会被跳过

Promise 中未捕获的错误不会终止脚本执行而是打印一个未捕获 promise 错误提示。

finally

finally 方法接受一个函数参数onFinally。它不管 Promise 对象最后状态如何,都会执行的操作。finally方法的回调函数不接受任何参数。

它返回一个设置了 finally 回调函数的Promise对象。

Promise.prototype.finally = function (callback) {
  let P = this.constructor;
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};

// finally 相当于返回一个已经带两个参数的 then 方法

Promise 方法

Promise 一共有 4 个静态方法。分别是all, race, resolvereject

resolve

resolve 接受一个参数,返回一个状态由给定value决定的Promise对象。

如果参数是 Promise 对象则直接返回。

如果参数是thenable(即,带有then方法的对象),then 方法会作为Promise的参数,立即执行。

如果是其他值返回一个新的 Promise 对象,状态为resolved,该value传递给对应的then方法。

Promise.resolve(1).then(num => {
    console.log(num)
});

reject

reject 方法接受一个参数,返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法。

Promise.reject('error');
// 等同于
new Promise((resolve, reject) => reject('error'))

all

all 方法接受具有 iterable 接口 参数。

这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。

这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致

如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。

参数中的每个项目都是一个 Promise 对象,如果不是则用 resolve 方法转换成 Promise 对象。

race

race 方法和 all 方法一样,但是当iterable参数里的任意一个子 Promise 被成功或失败后,返回的 Promise 对象的状态就变成这个子 Promise 对象的状态,它的值或错误信息也会传递给返回 Promise 对象的回调函数。

Promise 的属性

Promise 一共有两个属性,lengthprototype

length属性,其值总是为 1 (构造器参数的数目)。