深入浅出了解ES6 Promise的用法

126 阅读3分钟

前言

Promise是ES6中的提供的一个异步解决方案,主要是想用来解决异步调用回调的问题,它是一个链式的操作,在实际开发过程中其实有很多的地方都用到了promise,比如fetch api返回的就是一个promise对象,generator中的yield一般也会跟promise对象,ES8中的async await是promise和generator函数的封装,所以还是很有必要对promise有一个深入的了解。

基础

promise是一个异步操作返回的结果,它有三种状态,pending(等待)resolve(成功)reject(失败),状态只能由pending变为resolve或者rejecjt,并且是不可逆的, 一旦执行,也是不可停止的。

基本用法

promise支持链式调用,使用then方法接收resolve的操作,catch方法接收reject的操作,对应链式调用,必须在上一个then方法中返回一个promise对象

new Promise((resolve, reject) => {
    setTimeout(() => {
        if(true) {
            resolve('success')
        } else {
            reject('error')
        }
    },2000)
}).then(data => {
    // 成功resolve
    console.log(data)
    return new Promise(() => {
        resolve('ok')
    })
}).then(data => {
    console.log(data)
})catch(err => {
    // 失败reject
    console.log(err)
})

Promise必须传递一个函数作为参数,否则会报错

实例方法

promise对象中提供了三个常用的实例方法:then, catch, finally

then

promise中调用resolve时触发的方法, 一般情况下是成功时的处理

new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    },2000)
}).then(data => {
    console.lgo(data)
})

catch

promise中调用reject时触发的方法,一般情况下是异常时的处理,对于reject(),需要使用catch进行捕获,不然浏览器会有错误的提示,一个未捕获的错误

b8c8226d96c4411697587d64a39bad00_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.jpg

new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('error')
    },2000)
}).catch( err => {
    console.log(err)
})

finally

new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    },2000)
}).finally(() => {
    console.log('finally')
})

promise中不管状态如何变化,最终都会执行finally

静态方法

resolve

// 传递对象
const p1 = Promise.resolve({title: 'hello world'})
p1.then(data => {
    console.log(data) // {title: 'hello world'}
})

// 传递对象包括then方法
const thenObj = {
    then: () => {
        console.log('hello world') // 直接输出
    }
}
Promise.resolve(thenObj)
  1. 执行resolve后,会返回一个promise对象,在调用对象的then方法时,resolve中的参数会传递给then方法作为参数
  2. 如果resolve的参数对象中有then方法,则会直接执行then方法
  3. 如果resolve的参数传递的是一个promise对象,则直接返回

reject

与resolve方法类似,只不过调用reject后,是触发catch方法进行逻辑处理,如果reject参数对象中有catch方法,则不会向上面场景中的then方法被直接执行

all

Promise.all方法中传递的是一个数组,返回的是一个promise对象

数组的每个值都是一个promise对象,只有等待当每个promise对象中都执行了resolve方法后,才会触发then方法,只要有一个promise执行了reject,那么就会触发catch, 永远也不会触发then方法了

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p1')
    }, 2000)
})
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p2')
    }, 3000)
})
Promise.all([p1, p2]).then(data => {
    console.log(data)
}).catch(err => {
    console.lgo(err)
})

race

与all用法类似,Promise.race方法中传递的是一个数组,返回的是一个promise对象

只要数组中某个promise对象执行了resolve或者reject,那么就会触发对应的then或catch方法,其他promise对象的结果都会被丢弃掉

简单来说race只对最先有结果(不管结果是成功还是失败)的promise进行处理,其他的一律不管

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p1')
    }, 2000)
})
const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p2')
    }, 3000)
})
const p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('p3')
    }, 1000)
})
Promise.race([p1, p2, p3]).then(data => {
    console.log(data)
}).catch(err => {
    console.lgo(err)
})

错误捕获

catch

当promise中执行reject时,可以通过catch方法捕获

new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('error')
    }, 2000)
}).then(data => {
    console.log(data)
}).catch(err => {
    console.log(err) // 捕获reject的信息
})

unhandledrejection

除了通过catch对每个promise进行单独捕获,还可以通过unhandledrejection进行全局的错误捕获,但catch存在时,unhandledrejection不会被监听到

new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('error')
    }, 2000)
}).then(data => {
    console.log(data)
})

// 监听到promise的reject操作
window.addEventListener("unhandledrejection", (err) => {
    console.log(err)
})