Promise简介

  1. Promise是JS中引入的一种新的提供异步编程的解决方案,旧的方案是使用回调函数。异步编程通常在以下情景中使用:
    1. Node.js下的fs模块的文件操作
    2. 数据库操作
    3. Ajax(网络请求)
    4. 定时器
  2. 使用Promise的优势
    1. 指定回调函数的方式更加灵活:旧的解决方案在启动异步任务前指定;而Promise可以在异步任务结束后指定一个或者多个回调。
    2. 支持链式调用,可以解决回调地狱的问题。
    回调地狱:回调函数嵌套调用
    缺点如下:
    1. 代码可读性差
    2. 不方便异常处理
    
  3. 使用Promise的简单示例:封装Ajax操作
<div>
    <button id="btn">发送Ajax请求</button>
</div>
<script>
    const btn = document.querySelector("#btn")
    btn.addEventListener('click', function() {
        // 创建Promise
        sendAjax('http://api.apiopen.top/getJoke')
            .then((value) => {
                console.log(value)
            }).catch((reason) => {
                console.log(reason)
            })
    })

    function sendAjax(url, method = 'get', async = true) {
        return new Promise((resolve, reject) => {
            //1.创建对象
            const xhr = new XMLHttpRequest();
            //2.初始化
            xhr.responseType = 'json'
            xhr.open(method, url, async)
                //3.发送请求
            xhr.send()
                //4.处理响应结果
            xhr.onreadystatechange = function() {
                if (xhr.readyState === 4) {
                    // 判断响应状态码为2xx
                    if (xhr.status >= 200 && xhr.status < 300) {
                        // 请求响应成功则输出响应体
                        resolve(xhr.response)
                    } else {
                        // 失败则输出错误码
                        reject(xhr.status)
                    }
                }
            }
        })
    }
</script>

Promise理解

1.Promise中的状态
  1. Promise的状态就是一个Promise实例对象中的PromiseState属性。其值可能有三种:
    1. pending:未决定的。(初始状态)
    2. resolved/fullfilled:成功
    3. rejected:失败
  2. Promise的状态改变只有两种:由pending变为resolved、由pending变为rejected。一个Promise对象的状态只能改变一次,无论最终状态变为成功还是失败,都会有一个结果数据,成功的一般叫做value,失败的一般叫做reason
2.Promise对象的结果值
  1. Promise对象的结果值就是一个Promise实例对象的PromiseResult属性,保存着异步任务中对象成功或者失败的结果。resolve、reject函数可以对这个属性值进行修改。
const p = new Promise((resolve, reject) => {
    let flag = true
    if (flag) {
        resolve(100)
    }
})
// 其中PromiseState的值为fulfilled
// PromiseResult的值为100
console.log(p)
3.Promise中的相关方法
  1. util.promisify()方法:可以将回调函数风格的方法转化为Promise风格的函数。(nodejs中的方法)
  2. Promise构造函数:Promise(executor)。executor在Promise内部同步调用的。
    1. executor函数:一个执行器,例如(resolve, reject)=>{}
      1. resolve函数:在内部定义成功时调用的函数,例如(value) =>{}
      2. reject函数:在内部定义失败时调用的函数,例如(reason) =>{}
  3. Promise.prototype.then方法:then方法内可以指定成功的回调函数和失败的回调函数
  4. Promise.prototype.catch方法:catch方法指定失败的回调函数
  5. Promise.resolve方法:参数为成功的数据或者Promise对象
// 如果传入的参数为非Promise的对象,则返回的结果为成功的Promise对象
// 如果传入的参数为Promise对象,则参数的结果决定了resolve的结果。
  1. Promise.reject方法:参数为失败的原因,返回一个失败的Promise对象
  2. Promise.all方法:参数为promises,是一个包含n个promise的数组。返回一个新的Promise,只有所有的Promise都成功才成功,只要有一个失败就返回失败的Promise。
let p1 = new Promise((resolve, reject) => {
    resolve('OK')
})
let p2 = Promise.resolve(520)
let p3 = Promise.resolve("I Love You")
const result = Promise.all([p1, p2, p3])
// 返回成功的Promise,结果值为每个Promise的结果值组成的数组
console.log(result)
  1. Prommise.race方法:参数为promises,是一个包含n个promise的数组。返回一个新的Promise,第一个完成的promise的结果状态就是最终的结果状态。
3.Promise的几个关键问题
  1. 改变Promise对象的状态
    1. 通过resolve(value):如果当前是pending,就会变成resolved
    2. 通过reject(reason):如果当前是pending,就会变成rejected
    3. 抛出异常:如果当前是pending,就会变成rejected
    let p = new Promise((resolve, reject) => {
        throw '抛出异常'
    })
    // Promise对象的状态为rejected
    console.log(p)
    
  2. 为一个Promise对象指定多个成功或者失败的回调函数,是否都会调用:当Promise对象的状态由pending变为resolved或者由pending变为rejected时都会调用。
let p = new Promise(() => {

})
// p对象的状态还是pending,所以then函数不会执行
p.then(value => {
    console.log(value)
})
  1. 改变Promise状态和指定回调函数的先后问题:都有可能,正常情况下先指定回调再改变状态,但是也可以先改变状态再指定回调。
    1. 如何先改变状态再指定回调:在执行器中直接调用resolve/reject函数或者延迟更长时间才调用then
    2. 如何先指定回调再改变状态:在异步回调中调用resolve或者reject
    3. 得到数据的时机:
      1. 如果先指定的回调,那当状态发生改变时,回调函数才会调用,得到数据
      2. 如果先改变的状态,那么当指定回调时回调函数就会调用得到数据。
  2. Promise.then方法返回的新的Promise对象的结果状态:由then方法指定的回调函数执行的结果决定。
    1. 如果抛出异常:新的Promise变为rejected,reason为抛出的异常
    2. 如果返回的是非Promise的任意值:新的Promise变为resolved,value为返回的值
    3. 如果返回的是另一个新的Promise,此Promise的结果就会成为新的Promise的结果。
  3. Promise串联多个同步或者异步的任务:通过Promise的then方法返回一个新的Promise对象,可以进行then函数的链式调用
  4. Promise异常穿透:当使用Promise的then的链式调用时,可以在最后指定失败的回调;前面任何操作出了异常,都会传到最后失败的回调中处理。
  5. 如何中断在Promise中的then方法的链式调用:在then方法的回调函数中返回一个pending状态的Promise对象