JS异步编程之Promise—— ES6基础总结(七)

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

基本用法

1.创建一个Promise实例

const promise = new Promise((resolve, reject) => {
      // ... some asynchronous working
      if (/* fulfilled */){
        return resolve(value)
      } else {  // rejected
        return reject(error)
      }
    })
复制代码

Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolvereject 。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

  • resolve:

    pending ——> fulfilled;

    在异步操作成功时调用,并将异步操作的结果作为参数传递出去。

  • reject:

    pending ——> rejected;

    在异步操作失败时调用,并将异步操作的错误,作为参数传递出去。

一般来说,调用 resolvereject 以后, Promise 的使命就完成了,后继操作应该放到 then 方法里面,而不应该直接写在 resolvereject 的后面。所以,最好在它们前面加上 return 语句,这样就不会有意外。

2.Promise.prototype.then()

promise.then((value) => {
      // resolved
    }, (error) => {
      // rejected
    })
复制代码

then 方法可以接受两个回调函数作为参数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

  • 回调函数1:

    Promise对象的状态变为resolved时调用。

  • 回调函数2(可选):

    Promise对象的状态变为rejected时调用。

3.Promise.prototype.catch()

promise.then((value) => {
      // resolved
    }).catch((error) => {
        // 1.rejected
        // 2.then内部发生错误
    })
复制代码

Promise.prototype.catch 方法是 .then(null, rejection).then(undefined, rejection) 的别名,用于指定发生错误时的回调函数。

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个 catch 语句捕获。

一般来说,不要在 then 方法里面定义 Reject 状态的回调函数(即 then 的第二个参数),总是使用 catch 方法。

4.Promise.prototype.finally()

该方法是 ES2018 引入标准的。

promise.then(result => {
        // resolved
    }).catch(error => {
        // 1.rejected
        // 2.then内部发生错误
    }).finally(() => {
        // 与状态无关
    })
复制代码

finally 方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是 fulfilled 还是 rejected 。这表明, finally 方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。

finally 方法总是会返回原来的值。

finally 本质上是 then 方法的特例。

实现:

Promise.prototype.finally = function (callback) {
      let P = this.constructor
      return this.then(
        // 不管前面的 Promise 是fulfilled还是rejected,都会执行回调函数callback
        value  => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason })
      )
    }
复制代码

5.Promise.all([p1, p2])

const p = Promise.all([p1, p2])
复制代码

参数:

  • p1、p2都是 Promise 实例;
  • 如果不是 Promise 实例,则会先调用 Promise.resolve() 将其转为 Promise 实例;
  • 可以不是数组,但必须具备 Interator 接口。

返回值:

  1. 只有p1、p2的状态都变成 fulfilled ,p的状态才会变成 fulfilled ,此时p1、p2的返回值组成一个数组,传递给p的回调函数。
const p1 = new Promise((resolve) => {
        setTimeout(() => {
            console.log('p1')
            return resolve('p1 resolved')
        }, 3000)
    })
    
    const p2 = new Promise((resolve) => {
        setTimeout(() => {
            console.log('p2')
            return resolve('p2 resolved')
        }, 1000)
    })
    
    Promise.all([p1, p2]).then((result) => {
        console.log(result)
    })
复制代码

2.只要p1、p2之中有一个被 rejected ,p的状态就变成 rejected ,此时第一个被 reject 的实例的返回值,会传递给p的回调函数。

const p1 = new Promise((resolve) => {
        setTimeout(() => {
            console.log('p1')
            return resolve('p1 resolved')
        }, 3000)
    })

    const p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('p2')
            return reject('p2 rejected')
        }, 1000)
    })

    Promise.all([p1, p2]).then((result) => {
        console.log(result)
    }).catch((error) => {
        console.log(error)
    })
复制代码
  1. 如果作为参数的 Promise 实例,自己定义了 catch 方法,那么它一旦被 rejected ,并不会触发 Promise.all()catch 方法。
const p1 = new Promise((resolve) => {
        setTimeout(() => {
            console.log('p1')
            return resolve('p1 resolved')
        }, 3000)
    })
    
    const p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('p2')
            return reject('p2 rejected')
        }, 1000)
    }).catch((error) => {
        console.log(error)
    })
    
    Promise.all([p1, p2]).then((result) => {
        console.log(result)
    }).catch((error) => {
        console.log(error)
    })
复制代码

6.Promise.race([p1, p2])

const p = Promise.race([p1, p2])
复制代码

参数:

  • Promise.all(p1, p2)

返回值:

  1. 只要p1、p2之中有一个实例率先改变状态,p的状态就跟着改变。
// p2提前被rejected
    
    const p1 = new Promise((resolve) => {
        setTimeout(() => {
            console.log('p1')
            return resolve('p1 resolved')
        }, 3000)
    })
    
    const p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('p2')
            return reject('p2 rejected')
        }, 1000)
    })
    
    Promise.race([p1, p2]).then((result) => {
        console.log(result)
    })
    .catch((error) => {
        console.log(error)
    })
复制代码
// p1提前被resolved
    
    const p1 = new Promise((resolve) => {
        setTimeout(() => {
            console.log('p1')
            return resolve('p1 resolved')
        }, 1000)
    })
    
    const p2 = new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('p2')
            return reject('p2 rejected')
        }, 3000)
    })
    
    Promise.race([p1, p2]).then((result) => {
        console.log(result)
    })
    .catch((error) => {
        console.log(error)
    })
复制代码

7.Promise.resolve()

有时需要将现有对象转为 Promise 对象。

Promise.resolve('result')
    // 等价于
    new Promise(resolve => resolve('result'))
复制代码

8.Promise.reject()

Promise.reject('erroe')
    // 等价于
    new Promise((resolve, reject) => reject('error'))
复制代码

小结

Promise 使得异步编程更为简介与强大,本文主要通过几个简单demo介绍了 Promise 的基本使用,后续章节将会继续讲解其它异步编程方式。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章