Promise笔记

一、Promise解决了什么问题

js 复制代码
    function foo(par, successCallback, failCallback) {
        // setTimeout用来模拟网络请求
        setTimeout(() => {
            if(par === 'ywq') {
                successCallback({ status: 200, message: '成功获取到数据了' })
            } else {
                failCallback({ status: -1, message: '数据获取失败' })
            }
        }, 1000)
    }

    // 1.传入参数ywq, 结果为res: { status: 200, message: '成功获取到数据了' }
    foo('ywq', (res) => {
        console.log('res:', res)
    }, (err) => {
        console.log('err:', err)
    })

    // 2.传入参数yyy, 结果为err: { status: -1, message: '数据获取失败' }
    foo('yyy', (res) => {
        console.log('res:', res)
    }, (err) => {
        console.log('err:', err)
    }) 

上面代码可以拿到获取异步代码的结果,但是我们能看出什么问题呢?

  1. 需要自己编写命名成功和失败的回调函数
  2. 如果其他人来使用,需要仔细看代码,判断参数是用来做什么的

总之就是开发成本大,那么Promise就是解决了上面的问题,Promise更加规范的规定这些参数是做什么的,下面就让我们走进Promise的世界吧!

二、Promise的简单使用

js 复制代码
    function foo() {
        return '承诺(成功/失败)'
    }
    let result = foo()

上面是一段伪代码. 一个函数返回给我们一个承诺(这个承诺可能成功,也可能失败),当我们调用这个函数时,我们可以拿到这个承诺的成功与否.

js 复制代码
    const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            if(true) {
                resolve('我是成功的结果')
            }else {
                reject('我是失败的结果')
            }
        }, 300)       
    })
    promise.then(res => {
        console.log('res:', res)
    }, err => {
        console.log('err:', err)
    })

上面这段代码看不太懂没有关系,我们和下面这段代码结合起来看

js 复制代码
    class Animal {
        constructor(executor) {
            this.resolve = () => {}
            this.reject = () => {}
            executor(this.resolve, this.reject)
        }
    }
    const dog = new Animal((resolve, reject) => {

    })
  1. Promise是一个构造函数/类,接收一个参数.这个参数是一个回调函数,一旦被调用,立马会被执行.回调函数还接收两个参数,这两个参数分别又是回调函数
  2. 在Promise这个回调函数中写异步代码,异步代码取得成功的结果,就调用resolve函数;失败就调用reject函数
  3. 获取Promise的结果,通过对象的thenable方法获取,then也接收回调函数(可以是一个回调,也可以是两个回调.这里就说是两个,后续再说).分别对应上面的resolve,reject.成功与失败的回调

三、Promise的三种状态(pending, resolved/fulfilled, rejected)

js 复制代码
    new Promise((resolve, reject) => {
        console.log('--------') // ①
        resolve('111') // ②
        reject('222') // ③
        resolve('333')  // ④
        console.log('+++++++++') // ⑤
    }).then(res => {
        console.log('res:', res) 
    }, err => {
        console.log('err:', err)
    })
  1. 在Promise的executor中,Promise的状态为pending(不确定状态)
  2. 当执行resolve函数时,Promise的状态为resolved/fulfilled(已敲定状态)
  3. 当执行reject函数时,Promise的状态为rejected(已拒绝状态)
  4. Promise的状态一旦确定,就不可改变了

调用了resolve/reject函数后,executor后续代码并不影响执行,是因为执行then的时候,resolve/reject的代码才会执行(注意代码执行顺序)

四、Promise的resolve参数

  1. 当resolve的参数是普通值/对象时
js 复制代码
    new Promise((resolve, reject) => {
    // resolve(123) // ① res: 123
    // resolve('aaa') // ② res: aaa
    // resolve({name: 'ywq', age: 12}) // ③ res: { name: 'ywq', age: 12 }
    // resolve(null) // ④ res: null
    // resolve() // ⑤ res: undefined
    // resolve(Symbol()) // ⑥ res: Symbol()
    // resolve(function() {}) // ⑦ res: [Function (anonymous)]
    // resolve(['aaa', 'bbb', 'ccc']) // ⑧ res: [ 'aaa', 'bbb', 'ccc' ]
    }).then(res => {
        console.log('res:', res)
    })
  1. 当resolve的参数是一个Promise时,则当前Promise的状态由传入的Promise的结果决定(状态移交)
js 复制代码
    new Promise((resolve, reject) => {
        resolve(new Promise((resolve, reject) => {
            resolve('哈哈哈') // ①
            reject('嘿嘿嘿') // ②
        }))
    }).then(res => {
        console.log('res:', res)
    }, err => {
        console.log('err:', err)
    })

3.当resolve的参数是一个对象(对象有实现then方法),则会执行这个then方法,并且当前Promise的状态由then方法决定(状态移交)

js 复制代码
    new Promise((resolve, reject) => {
        resolve({
            then: function(resolve, reject) {
                resolve('是我resolve') // ①
                reject('是我reject') // ②
            }
        })
    }).then(res => {
        console.log('res:', res)
    }, err => {
        console.log('err:', err)
    })

五、Promise的对象方法-then

then的参数

js 复制代码
    new Promise((resolve, reject) => {
        resolve('我是正确的') // ① 
        reject('我是错误的') // ②
    }).then((res) => {
        console.log('我是成功时被执行了', res)
    }, (err) => {
        console.log('我是失败时被执行了', err)
    })
  • then方法可以接收两个回调函数

    第一个回调函数是执行resolve时被回调,可以接收参数,参数是resolve的结果

    第二个回调函数是执行reject时被回调,可以接收参数,参数是rejected的结果

js 复制代码
    const promise = new Promise((resolve, reject) => {
        reject('太丑了')
    })
    promise.then(res => {
        console.log('哈哈,我被接受了')
    })
    promise.catch(err => {
        console.log(`额,我被拒绝了,原因是${err}`)
    })
  • then方法可以接受一个回调函数(成功捕获和错误捕获可以分开写)

    成功捕获使用 then

    错误捕获使用 catch

    在node环境中打印会报错(This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch()),原因是因为我们通过then和catch分别去获取结果(互不相干),当Promise异步代码发生异常,then方法并没有去捕获错误

then方法可以被多次调用

js 复制代码
    const promise = new Promise((resolve, reject) => {
        resolve('呵呵呵呵呵')
    })
    promise.then(res => { console.log('res1:', res) }) // ① res1: 呵呵呵呵呵
    promise.then(res => { console.log('res2:', res) }) // ② res2: 呵呵呵呵呵
    promise.then(res => { console.log('res3:', rves) }) // ③ res3: 呵呵呵呵呵
  • resolve方法被回调时,所有的then方法传入的回调函数都会被调用

六、 Promise的链式调用/then方法可以有返回值

js 复制代码
    new Promise((resolve, reject) => {
        resolve('a')
    }).then(res => {
        console.log('获取了第一个的正确结果:', res)
        return 'b' // ①
        return new Promise((resolve, reject) => {
            setTimeout(() => { reject(333) }, 300)
        }) // ②
        return { then: function(resolve, reject) { reject(444) } } // ③
    }, err => {
        console.log('获取了第一个的错误结果:', err)
    }).then(res => {
        console.log('获取了第二个的正确结果:', res)
    }, err => {
        console.log('获取了第二个的错误结果:', err)
    })
  • then方法的回调函数可以有返回值,返回值会被作为一个新的Promise
    1. 返回普通的值/对象 普通的值/对象会被作为新的Promise的resolve值
    2. 返回一个新的Promise
    3. 返回一个实现thenable方法的对象

七、Promise的对象方法-catch

上面我们讲了promise的两种错误捕捉catch

  1. then方法的第二个回调函数
  2. Promise对象的catch方法单独调用

第三种

  1. 用于Promise的链式调用的尾部
js 复制代码
    new Promise((resolve, reject) => {
        resolve('正确111') // ①
        reject('错误111') // ②
    }).then(res => {
        return new Promise((resolve, reject) => { resolve('正确222') }) // ③
        return new Promise((resolve, reject) => { reject('错误222') }) // ④
    }).then(res => {
        return { name: 'ywq' }
    }).catch(err => {
        console.log('err:', err)
    })
  • catch是依次捕捉Promise的错误结果.第一个Promise如果错误,就可以打印catch的错误结果;如果正确,会捕捉下一个Promise的错误...依次类推
js 复制代码
    new Promise((resolve, reject) => {
        reject('err1') // ① err: err1
        throw new Error('err2') // ② err: Error: err2
    }).then(res => {}, err => { 
        console.log('err:', err) 
    })
  • 当executor中的代码出现异常错误,也会被捕获到

then的错误捕获也可以有返回值,返回值也是一个新的Promise,同then的成功捕获一样

js 复制代码
    new Promise((resolve, reject) => {
        reject('a')
    }).then(() => {}, err => {
        console.log('获取了第一个的错误结果:', err)
        return '错误b' // ①
        return new Promise((resolve, reject) => { resolve('正确c') }) // ②
        return new Promise((resolve, reject) => { reject('错误c') }) // ③
        return ({ then: function(resolve, reject) { resolve('正确d') }}) // ④
        return ({ then: function(resolve, reject) { reject('错误d') }}) // ⑤
    }).then(res => {
        console.log('获取了第二个的正确结果:', res)
    }, err => {
        console.log('获取了第二个的错误结果:', err)
    })

八、Promise的对象方法-finally

js 复制代码
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('success') // ①
            reject('fail') // ②
        }, 300)
    }).then(res => {
        console.log('res:', res)
    }).catch(err => {
        console.log('err:', err)
    }).finally(() => {
        console.log('finally的回调函数被执行了')
    })
  • finally也接收一个回调函数.这个回调函数没有参数,不管Promise的状态是resolved/rejected,最终都会被执行.这个回调函数主要用来做清除工作.

九、Promise的6个类方法

Promise.resolve

js 复制代码
    // 将一个对象变为一个Promise  (pending => resolved)
    new Promise((resolve) => { resolve({ name: 'ywq' }) })
        .then(res => { console.log('res:', res) })

    // 上面代码等同于
    Promise.resolve({ name: 'ywq' })
        .then(res => { console.log('res:', res) })
js 复制代码
    // 测试
    Promise.resolve(123)
        .then(res => { console.log('res:', res) }) // ① res: 123

    Promise.resolve({then: function(resolve) { resolve('哈哈哈') }})
        .then(res => { console.log('res:', res) }) // ② res: 哈哈哈

    Promise.resolve(new Promise((resolve) => resolve({ name: 'ywq' })))
        .then(res => { console.log('res:', res) }) // ③ res: { name: 'ywq' }
  • 如果明确将"某个值/对象/对象实现了thenable方法/新的Promise"转变为Promise已敲定状态,可以直接使用Promise.resolve()

Promise.reject

js 复制代码
    // 将一个对象变为一个Promise (pending => rejected)
    new Promise((resolve, reject) => { reject({ name: 'ywq' }) })
        .then(res => { })
        .catch(err => { console.log('err:', err) })

    // 上面代码等同于
    Promise.reject({ name: 'ywq' })
        .then(() => {})
        .catch(err => { console.log('err:', err) })
js 复制代码
    // 测试
    Promise.reject(123)
        .then(res => { console.log('res:', res) })
        .catch(err => { console.log('err:', err) }) // ① err: 123

    Promise.reject({then: function(resolve) { resolve('哈哈哈') }})
        .then(res => { console.log('res:', res) })
        .catch(err => { console.log('err:', err) }) // ② err: { then: [Function: then] }

    Promise.reject(new Promise((resolve) => resolve({ name: 'ywq' })))
        .then(res => { console.log('res:', res) })
        .catch(err => { console.log('err:', err) }) // ③ err: Promise { { name: 'ywq' } }
  • 如果明确转变为Promise已拒绝状态,"传入任何值都是已拒绝状态",可以直接使用Promise.reject() !!!特别注意

这是一段公共代码

js 复制代码
    const promise1 = new Promise((resolve, reject) => { 
        setTimeout(() => {
            resolve('promise1_resolved') // ①      
            reject('promise1_rejected') // ②
        }, 1000)
    })
    const promise2 = new Promise((resolve, reject) => { 
        setTimeout(() => {
            resolve('promise2_resolved') // ③
            reject('promise2_rejected') // ④
        }, 2000)
    })
    const promise3 = new Promise((resolve, reject) => { 
        setTimeout(() => {
            resolve('promise3_resolved') // ⑤
            reject('promise3_rejected') // ⑥
        }, 3000)
    })

Promise.all

js 复制代码
    const arr = [ promise1, promise2, promise3, 123, { name: 'ywq' } ]
    Promise.all(arr).then(res => {
        console.log('res:', res)
    }, err => {
        console.log('err:', err)
    })
  • Promise.all接收一个数组,数组里面的参数都会转变为Promise,按传入参数的顺序,依次执行每个Promise
  • 当所有Promise的状态为resolved时,返回一个数组
  • 当只要有一个Promise的状态为rejected时,整个Promise数组的状态就为rejected,并立即暂停执行后续每个Promise

Promise.allSettled

js 复制代码
    const arr = [ promise1, promise2, promise3, 123, { name: 'ywq' } ]
    Promise.allSettled(arr).then(res => {
        console.log('res:', res)
    })
  • Promise.allSettled接收一个数组,数组里面的参数都会转变为Promise,按传入参数的顺序,依次执行每个Promise

  • 每个Promise都会被执行,不管状态是否为rejected/fulfilled.永远不会执行catch

    返回结果eg: [{ status: 'rejected', reason: 'xxxx' }, { status: 'fulfilled', value: 'xxxx' }]

Promise.race

js 复制代码
    const arr = [ promise1, promise2, promise3 ]
    Promise.race(arr).then(res => {
        console.log('res:', res)
    }, err => {
        console.log('err:', err)
    })
  • Promise.allSettled接收一个数组,数组里面的参数都会转变为Promise,按传入参数的顺序,依次执行每个Promise
  • 只要pending状态最先被改变了,立马结束. 结果为最先得到结果的那个Promise(不管Promise是fulfilled状态还是rejected状态)

Promise.any

js 复制代码
    const arr = [ promise1, promise2, promise3 ]
    Promise.any(arr).then(res => {
        console.log('res:', res)
    }, err => {
        console.log('err:', err)
    })
  • Promise.any接收一个数组,数组里面的参数都会转变为Promise,按传入参数的顺序,依次执行每个Promise
  • 结果为最先返回状态为fulfilled的那个Promise.
  • 如果所有的Promise都为rejected状态,结果为eg: [AggregateError: All promises were rejected] { [errors]: [ 'xxx', 'xxx', 'xxx' ] }
相关推荐
王哲晓39 分钟前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
理想不理想v44 分钟前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云1 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js
aPurpleBerry2 小时前
JS常用数组方法 reduce filter find forEach
javascript
ZL不懂前端2 小时前
Content Security Policy (CSP)
前端·javascript·面试
乐闻x2 小时前
ESLint 使用教程(一):从零配置 ESLint
javascript·eslint
我血条子呢3 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
半开半落3 小时前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt
理想不理想v4 小时前
vue经典前端面试题
前端·javascript·vue.js