【JS】Promise API

81 阅读3分钟

一、Promise.resolve()

  1. 作用

将现有对象转换成 Promise 对象,这个现有对象可以是普通数据(对象),转换为 Promise 对象后状态为 fulfilled,也可以是 Promise 对象,二次转换为 Promise 对象后状态为原本的状态。前者具有一定的应用价值

  1. 应用 —— 缓存数据

在单页面应用中,组件的频繁切换可能会导致频繁地请求,但短时间内数据并没有变化,所以可以利用 Promise.resolve() 将第一次的请求数据转换成 Promise 对象,实现后续 then 的调用

function ajax(url){
    // 取出 挂载在 ajax 函数对象身上的 缓存数据
    var cache = ajax.cache || (ajax.cache = {data:null})
    // 如果有缓存数据
    if(cache.data){
        console.log("走缓存")
        // 将缓存的数据转换成 Promise 对象
        return Promise.resolve(cache.data)
    }
    
    // 如果没有缓存数据,返回 Promise 对象
    return new Promise((resolve, reject) => {
        // 发送 ajax 请求
        var xhr = new XMLHttpRequest()
        xhr.open('get', url, true)
        xhr.send()
        xhr.onreadystatechange = function(){
            if(xhr.readyState === 4){
                if(xhr.status >= 200 && xhr.status < 300){
                    // 成功
                    resolve(JSON.parse(xhr.responseText))
                    console.log('不走缓存')
                    // 缓存数据 —— 挂载在 ajax 函数对象身上
                    ajax.cache.data = JSON.parse(xhr.responseText)
                } else {
                    // 失败
                    reject(xhr.responseText)
                }
            }
        }
    })
}

// 第一次发请求 —— 不会走缓存
ajax('http://...').then((data) => {...})

// 第二次发请求 —— 会走缓存
setTimeout(() => {
    ajax('http://...').then((data) => {...})
}, 1000)

// 第三次发请求 —— 不想走缓存
setTimeout(() => {
    // 可先清空缓存
    ajax.cache = null;
    // 再发请求,不会走缓存
    ajax('http://...').then((data) => {...})
}, 2000)

二、Promise.reject()

  1. 作用

将普通数据(对象)转换成 Promise 对象,状态为 rejected,也可将 Promise 对象二次转换成 Promise 对象,状态为原来的状态

三、Promise.all()

  1. 作用

将多个 Promise 实例,包装成一个新的 Promise 实例

const p = Promise.all([p1, p2, p3])
// p 的状态由 p1,p2,p3 决定
// 只有 p1,p2,p3 的状态都变成 fulfilled,p 的状态才会变成 fulfilled,此时 p1,p2,p3 的返回值组成一个数据,传递给 p 的回调函数
// 只要 p1,p2,p3 之中有一个被 rejected,p 的状态就变成 rejected,此时第一个被 rejected 的实例的返回值,会传递给 p 的回调函数
  1. 应用
// 发送多个 ajax 请求

// 请求数据
var list = ['zs', 'li', 'ww']
// 请求函数
function getData(list) {
    // 将数组中的普通对象,映射成 Promise 对象
    var newlist = list.map(item => ajax(`http://...?name=${item}`))
    // 将一个由 Promise 对象组成的数组包装成一个 Promise 对象,并返回
    return Promise.all(newlist)
}

// 调用函数,发送请求
getData(list)
.then((res) => {
    // 所有 Promise 均没有错误才 fulfilled
})
.catch((err) => {
    // 处理 Promise 数组中第一个出现的错误
})

四、Promise.race()

  1. 作用

将多个 Promise 对象,包装成一个新的 Promise 对象

const p = Promise.race([p1, p2, p3])
// 只要 p1,p2,p3 中有一个对象率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 对象的返回值,就传递给 p 的回调函数
  1. 应用 —— 超时检测
// ajax 请求
var p1 = ajax('http://...')

// 定时器 Promise 对象
var p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject('超时')
    }, 2000)
})

Promise.race([p1, p2]).then(res => {
    // 如果 p1 先 fulfilled
    console.log(res)
}).catch(err => {
    // 如果 p2 先 rejected
    console.log(err)
})

五、Promise.allSettled()

  1. 作用

用来确定一组异步操作是否都结束了(不管成功或失败),包含了 fulfilled 和 rejected 两种情况

  1. 应用
const promises = [ ajax('/200接口'), ajax('/401接口')]

Promise.allSettled(promises)
.then(res => {
    // 过滤出成功的请求
    var successRes = res.filter(item => item.status === 'fulfilled')
    // 过滤出失败的请求
    var errorRes = res.filter(item => item.status === 'rejected')
})

六、Promise.any()

  1. 作用

只要 Promise 对象有一个变成 fulfilled 状态,包装对象就会变成 fulfilled 状态(如果有多个 fulfilled,则取第一个);如果所有 Promise 对象都变成 rejected 状态,包装对象才会变成 rejected 状态

  1. 应用
var p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        // resolve('p1 成功')
        reject('p1 失败')
    }, 1000)
})

var p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        // resolve('p2 成功')
        reject('p2 失败')
    }, 2000)
})

var p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p3 成功')
    }, 3000)
})

Promise.any([p1, p2, p3])
.then(res => {
    // 只要有一个成功,就会执行 then
    console.log(res)
})
.catch(err => {
    // 只有全部都失败,才会执行 catch
    console.log(err)
})