Promise

作者: jackie季 | 来源:发表于2018-09-02 18:12 被阅读0次

    Promise是一种异步编程的解决方案,比传统的回调函数更强大更优雅,结构更清晰
    Promise是一个容器,里面保存着某个未来即将发生的事情,通常是一个异步操作,它有三种状态,pedding(进行中)、resolved(已成功)、rejected(已失败),只有异步操作的结果才能决定当前状态;一旦状态改变就不会再变了,而且只有两种变化的方式,从pedding→resolved或从pedding→rejected

    在ES6中规定Promise是构造函数,用来生成一个promise对象,构造函数的参数是一个函数,这个函数有两个参数:resolve和reject,这两个参数也是函数,异步操作成功时(pedding→resolved)调用resolve(),操作失败时(pedding→rejected)调用reject()
    Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数

    简单例子:

    function timeout(ms) {
      return new Promise((resolve, reject) => {
        setTimeout(resolve, ms, 'done')
      })
    }
    timeout(100).then((value) => {
      console.log(value)
    })
    

    Promise新建后会立即执行,然后then指定的回调函数会在当前同步任务执行完再执行

    let promise = new Promise(function(resolve, reject) {
      console.log('Promise')
      resolve()
    })
    promise.then(function() {
      console.log('resolved.')
    })
    console.log('Hi!')
    
    // Promise
    // Hi!
    // resolved
    

    用Promise实现 Ajax

    const getJSON = function(url) {
      const promise = new Promise(function(resolve, reject){
        const handler = function() {
          if (this.readyState !== 4) {
            return
          }
          if (this.status === 200) {
            resolve(this.response)
          } else {
            reject(new Error(this.statusText))
          }
        }
        const client = new XMLHttpRequest()
        client.open("GET", url)
        client.onreadystatechange = handler
        client.responseType = "json"
        client.setRequestHeader("Accept", "application/json")
        client.send()
      })
      return promise
    }
    getJSON("/posts.json").then(function(json) {
      console.log('Contents: ' + json)
    }, function(error) {
      console.error('出错了', error)
    })
    

    如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个 Promise 实例,此时的状态则由参数的Promise实例的状态决定。

    Promise.prototype.then

    then方法是定义在原型Promise.prototype上的,所以Promise实例对象也具有then方法,它的作用是为Promise实例添加状态改变时的回调函数,第一个参数是状态变为resolved时的回调函数,第二个参数是状态变为rejected时的回调函数(可省略)
    then的返回值是一个新的Promise实例,所以可以采用链式写法,在then方法后面再调用另一个then方法,并且第一个then回调的结果会作为参数传给第二个then的回调函数

    getJSON("/posts.json").then(function(json) {
      return json.post
    }).then(function(jsonPost) {
      // ...
    })
    

    Promise.prototype.catch

    catch方法同样位于原型中,用于指定发生错误时的回调函数

    getJSON('/posts.json').then(function(posts) {
      // ...
    }).catch(function(error) {
      // 处理 getJSON 和 前一个回调函数运行时发生的错误
      console.log('发生错误!', error)
    })
    

    Promise抛出错误(throw),会被catch方法捕获,reject方法的作用,等同于抛出错误,也会被catch捕获

    const promise = new Promise(function(resolve, reject) {
      reject(new Error('test'))
    })
    promise.catch(function(error) {
      console.log(error)
    })
    // Error: test
    

    如果 Promise 状态已经变成resolved,再抛出错误是无效的,因为Promise状态一旦改变,就不会再变

    const promise = new Promise(function(resolve, reject) {
      resolve('ok')
      throw new Error('test')
    })
    promise
      .then(function(value) { console.log(value) })
      .catch(function(error) { console.log(error) })
    // ok
    

    Promise对象的错误有冒泡性质,会一直向后传递,直到被捕获为止

    getJSON('/post/1.json').then(function(post) {
      return getJSON(post.commentURL)
    }).then(function(comments) {
      // some code
    }).catch(function(error) {
      // 处理前面三个Promise产生的错误
    })
    

    上面代码中,一共有三个 Promise 对象:一个由getJSON产生,两个由then产生。它们之中任何一个抛出的错误,都会被最后一个catch捕获

    一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),建议在Promise 对象后面跟着catch方法
    catch方法返回的还是一个 Promise 对象,后面还可以接着调用then方法,如果没有报错,则会跳过catch方法,如果后面的then报错了则与前面的catch无关了
    如果catch方法中有错误,后面可以再接着catch捕获前一个catch的错误

    Promise.prototype.finally

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

    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···})
    

    Promise.all

    Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例,其接受一个数组作为参数,数组中每个元素都是 Promise 实例,如果不是就会调用Promise.resolve方法转为 Promise 实例

    const p = Promise.all([p1, p2, p3]);
    

    p的状态由p1、p2、p3决定,存在两种情况:
    (1)只有p1、p2、p3的状态都变成resolved,p的状态才会变成resolved,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
    (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

    Promise.race

    Promise.race方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例,参数与Promise.all方法一样。

    const p = Promise.race([p1, p2, p3])
    

    只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

    const p = Promise.race([
      fetch('/resource-that-may-take-a-while'),
      new Promise(function (resolve, reject) {
        setTimeout(() => reject(new Error('request timeout')), 5000)
      })
    ])
    p
    .then(console.log)
    .catch(console.error)
    

    上面代码中,如果 5 秒之内fetch方法无法返回结果,变量p的状态就会变为rejected,从而触发catch方法指定的回调函数。

    Promise.resolve

    Promise.resolve()方法可以将现有对象转为 Promise 对象

    Promise.reject

    Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

    相关文章

      网友评论

          本文标题:Promise

          本文链接:https://www.haomeiwen.com/subject/oenywftx.html