ES6之Promise原理及常用的api

前言:

1.Promise原理解析

2.后面部分讲 then,resolve与reject,all,race的操作

一.Promise原理

先看原理图:

①执行new Promise时会返回一个空状态(pending挂起状态),此时返回的是undefined(既不是成功,也不是失败

②Promise内部有两个方法,resolve和reject。resolve是将pending状态变为完成(fulfilled)状态,返回结果(result);而reject是将pending状态变为拒绝(rejected)状态,返回结果error。切记,状态是不可逆的,只能从pending到fulfilled或rejected。

二.Promise.prototype.then(onFulfilled, onRejected)方法

1.只要是promise对象就支持Promise语法,就能用then。

2.then支持两个参数,两个参数onFulfilled,onFulfilled都是函数类型的,而且onFulfilled和onFulfilled对应Promise的resolve和reject两个方法,因为这两个方法返回两个不同的状态.

3.如果then里面传的是非函数,就会返回一个空的Promise对象,这家就能保证调用then就一定能够返回一个then对象,这样子就能完全保证我们能够实用连续的then的链式调用.

代码1:

function loadScript (src) {
  return new Promise((resolve, reject) => {
    let script = document.createElement("script");
    script.src = src;
    script.onload = () => resolve(src);
    script.onerror = (err) => reject(err);
    document.head.append(script);
  })
}

loadScript("./1.js")
  .then(loadScript("./2.js"))
  .then(loadScript("./3.js"))

//返回1 2 3
//./1.js ./2.js ./3.js均来自静态文件

说明:①上面代码中,then里面提供非函数 (nonfunction) 参数,那么 then 方法将会丢失关于该状态的回调函数信息,但是并不会产生错误,上面代码返回的pending状态。

代码2:

function loadScript (src) {
  return new Promise((resolve, reject) => {
    let script = document.createElement("script");
    script.src = src;
    script.onload = () => resolve(src);
    script.onerror = (err) => reject(err);
    document.head.append(script);
  })
}
  
loadScript("./1.js")
    .then(() => {
      // 如果不加return则返回一个空的Promise对象,因为loadScript('./4.js')不是函数
      // 如果加上return就是返回一个新的Promise实例去影响下一个then的状态
      return loadScript('./42.js')
    }, (err) => {
      console.log(err)
    })
    .then(() => {
      loadScript('./3.js')
    }, (err) => {
      console.log(err)
    })

说明:

①如果不加return,依旧是个非函数(因为loadScript('./4.js')不是函数),则返回一个空的Promise对象。

②如果加上return就是返回一个新的Promise实例去影响下一个then的状态

代码3:then的正规操作

function loadScript (src) {
  return new Promise((resolve, reject) => {
    let script = document.createElement("script");
    script.src = src;
    script.onload = () => resolve(src);
    script.onerror = (err) => reject(err);
    document.head.append(script);
  })
}
  
loadScript("./4.js").then((value) => {
    console.log(value)
  }, (err) => {
    console.log(err)
  })

结果:

说明:这是正常执行的结果,里面写的都是函数

三、Promise.resolve与Promise.reject的使用

        一般情况下我们都会使用 new Promise() 来创建 Promise 对象,但是除此之外我们也可以使用其他方法。在这里,我们将会学习如何使用 Promise.resolve 和 Promise.reject 这两个静态方法。

代码:

  function cap (type) {
    if(type){
      return Promise.resolve(42)
    } else {
      return Promise.reject(new Error("出错了"))
    }
  }

  cap(0).then((value) => {
    console.log(value)
  }, (err) => {
    console.log(err)
  })

结果:

说明:

①如果直接返回的是数据,而且又想使用then方法,可以直接用静态方法里面写入数据,然后用then去调用,如上代码所示。

四、Promise.prototype.catch()方法

      捕获异常是程序质量保障最基本的要求,可以使用 Promise 对象的 catch 方法来捕获异步操作过程中出现的任何异常。

代码1:

function loadScript (src) {
  return new Promise((resolve, reject) => {
    let script = document.createElement("script");
    script.src = src;
    script.onload = () => resolve(src);
    script.onerror = (err) => reject(err);
    document.head.append(script);
  })
}
 
 loadScript("./1.js")
    .then(() => {
      return loadScript('./42.js')
    })
    .then(() => {
      loadScript('./3.js')
    }).catch(err => {
      console.log(err)
    })

结果:

说明:catch() 方法返回一个Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。

代码2:代码比较

// 代码1
function test () {
  return new Promise((resolve, reject) => {
    throw new Error('wrong')
  })
}

test().catch((e) => {
  console.log(e.message) // wrong
})

// 代码2
function test () {
  return new Promise((resolve, reject) => {
    reject(new Error('es'))
  })
}

test().catch((e) => {
  console.log(e.message) // es
})

问题:这个代码展示了如何使用 catch 捕获 Promise 对象中的异常,有的同学会问 catch 捕获的是 Promise 内部的 Error 还是 Reject?上面的示例既用了 reject 也用了 Error,到底是哪个触发的这个捕获呢?

答:如上代码,代码1对比着上个代码2就能明显感受出来的,throw Error 和 reject 都触发了 catch 的捕获,而第2个用法中虽然也有 Error 但是它不是 throw,只是 reject 的参数是 Error 对象,换句话说 new Error 不会触发 catch,而是 reject。

说明:不建议在 Promise 内部使用 throw 来触发异常,而是使用 reject(new Error()) 的方式来做,因为 throw 的方式并没有改变 Pronise 的状态

五、Promise.all(promiseArray)方法

var p1 = Promise.resolve(1)
var p2 = Promise.resolve(2)
var p3 = Promise.resolve(3)
Promise.all([p1, p2, p3]).then(function (results) {
  console.log(results) // [1, 2, 3]
})

 说明:

①Promise.all 生成并返回一个新的 Promise 对象,所以它可以使用 Promise 实例的所有方法。参数传递promise数组中所有的 Promise 对象都变为resolve的时候,该方法才会返回, 新创建的 Promise 则会使用这些 promise 的值。

②如果参数中的任何一个promise为reject的话,则整个Promise.all调用会立即终止,并返回一个reject的新的 Promise 对象。

③由于参数数组中的每个元素都是由 Promise.resolve 包装(wrap)的,所以Paomise.all 可以处理不同类型的 promose对象。

六、 Promise.race(promiseArray)方法

场景:比如说有两条线路,你想快速的获得某一条线路等等,优点像CDN

返回值:一个待定的 Promise 只要给定的迭代中的一个promise解决或拒绝,就采用第一个promise的值作为它的值,从而异步地解析或拒绝(一旦堆栈为空)。

代码:

  const fn1 = () => {
    return new Promise((resolve, reject) =>{
      setTimeout(()=>{
        resolve(111)
      },2000)
    })
  }

  const fn2 = () => {
    return new Promise((resolve, reject) => {
      setTimeout(() =>{
        resolve(222)
      }, 1000)
    })
  }

  Promise.race([fn1(), fn2()]).then((value) => {
    console.log(value)//222
  })
  

说明:

①因为fn2的时间在1000mm,而fn1的时间在2000mm,所以fn2快于fn1,所以fn2先返回了

七、用Promise写一个接口

  function getUrl (url) {
    return new Promise((resolve, reject) => {
      let xml = new XMLHttpRequest()
      xml.onreadystatechange = function() {
        if (xml.ready === 4) {
          if (xml.status === 200) {
            resolve(JSON.parse(xml.responseText))
          }
          else if (xml.status === 404) {
            reject(new Error('错误信息404'))
          }
        }
      }
      xml.send(null)
    })
  }
  
  const url = './jsonp.json'
  getUrl(url).then((res) => {
    console.log(res)
  })
发布了62 篇原创文章 · 获赞 11 · 访问量 8614

猜你喜欢

转载自blog.csdn.net/qq_38588845/article/details/103615774
今日推荐