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' ] }
相关推荐
Fan_web13 分钟前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
Jiaberrr1 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
安冬的码畜日常3 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
太阳花ˉ3 小时前
html+css+js实现step进度条效果
javascript·css·html
john_hjy4 小时前
11. 异步编程
运维·服务器·javascript
风清扬_jd4 小时前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
yanlele4 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
It'sMyGo4 小时前
Javascript数组研究09_Array.prototype[Symbol.unscopables]
开发语言·javascript·原型模式
xgq5 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试