清淨
  • Java

    • Java 基础
  • 框架

    • Flyway
    • MapStruct
    • Spring Cloud
  • 中间件

    • Elasticsearch
    • Redis
    • RabbitMQ
    • Kafka
  • 三剑客

    • HTML
    • CSS
    • JavaScript
  • 进阶

    • jQuery
    • ECMAScript6
    • TypeScript
  • Vue

    • Vue2
    • Vue3
    • VuePress
  • Linux
  • Jenkins
  • Maven
  • MySQL
  • 插件工具
  • 代码集成
  • 其它

    • 数据结构与算法
    • 计算机网络
    • 操作系统
    • 设计模式
迁移日志
订阅号
微信订阅号
微信订阅号
GitHub
  • Java

    • Java 基础
  • 框架

    • Flyway
    • MapStruct
    • Spring Cloud
  • 中间件

    • Elasticsearch
    • Redis
    • RabbitMQ
    • Kafka
  • 三剑客

    • HTML
    • CSS
    • JavaScript
  • 进阶

    • jQuery
    • ECMAScript6
    • TypeScript
  • Vue

    • Vue2
    • Vue3
    • VuePress
  • Linux
  • Jenkins
  • Maven
  • MySQL
  • 插件工具
  • 代码集成
  • 其它

    • 数据结构与算法
    • 计算机网络
    • 操作系统
    • 设计模式
迁移日志
订阅号
微信订阅号
微信订阅号
GitHub
  • ECMAScript6

    • 简介
    • let
    • const
    • 解构赋值
    • 对象简写
    • 箭头函数
    • 参数默认值
    • 剩余参数
    • 可选链操作符
    • 空值合并运算符
    • 逻辑空赋值
    • 模板字符串
    • 扩展运算符 (展开语法)
    • Array 扩展
    • String 扩展
    • Number 扩展
    • Object 扩展
    • 迭代器
    • 生成器
    • BigInt
    • Set
    • Map
    • class
    • 模块化
    • globalThis
    • Promise
    • async-await

Promise

Promise 是 ES6 中新增的一个对象,它用来表示一个异步操作的最终完成(或失败)及其结果值。它可以让我们更好地处理异步操作,避免回调地狱的问题。

1. Promise 能做什么?

它是用来解决异步编程的一种方案。

2. 什么时候可以使用异步事件?

最常见的就是网络请求。

3. 为什么有了 Ajax 还需要使用 Promise?

因为在 Ajax 的回调函数中可能有存在其它的网络请求(即回调地狱),这时就可以使用 Promise 来优雅地解决这个问题。

基本用法

// resolve 和 reject 是函数
new Promise((resolve, reject) => {
  // 第一次网络请求
  setTimeout(() =>{
    resolve()
  },1000)
}).then(() => {
  // 第一次网络请求之后的处理
  console.log('hello')

  // 第二次网络请求
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve()
    }, 1000)
  })
}).then(() => {
  // 第二次网络请求之后的处理
  console.log('hello1')

  // 第三次网络请求
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve()
    }, 1000)
  })
}).then(() => {
  // 第三次网络请求之后的处理
  console.log('world')
})

以上代码的等价形式如下:

setTimeout(() => {
  console.log('hello1')
  setTimeout(() => {
    console.log('hello2')
    setTimeout(() => {
      console.log('hello3')
    }, 1000)
  }, 1000)
}, 1000)

在使用 Promise 时,需要创建一个实例(即 new Promise())。在创建实例时,需要通过构造方法传递一个函数(函数的两个参数都是函数(参数可选)),且传入的函数会被立即执行,在异步操作需要使用回调的地方调用 resolve() 方法,然后在 then() 方法中执行回调方法的处理即可。定时器本身就是异步事件。

接下来模拟一个异步回调传参的情况:

// 以下是伪代码
new Promise((resolve, reject) => {
  $.ajax({
    url: ,
    // 执行成功回调,并得到后台的响应数据 data
    success: (data) => {
      resolve(data)
    },
    error: (err) => {}
  })
}).then(/* 此 data 就是 ajax 成功时回调函数传入的数据 */ (data) => {})

/* -------------------------------------- */

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('hello promise')
  }, 1000)
}).then((data) => {
  console.log(data) // hello promise
})

上面我们只使用了 resolve() 函数,接下来介绍一下 reject 的使用。其实,我们可以简单理解为 resolve() 用来处理请求成功,reject() 用来处理请求失败的情况,而且请求失败时是通过 catch 来进行回调的处理(也可使用 then 的第二个参数)。

new Promise((resolve, reject) => {
  $.ajax({
    url: '',
    success: (data) => { resolve(data) },
    error: (err) => { reject(err) }
  })
}).then((data) => {
  // 请求成功
}).catch(err => {
  // 请求失败
})

/* -------------------------------- */

new Promise((resolve, reject) => {
  $.ajax({
    url: '',
    success: (data) => { resolve(data) },
    error: (err) => { reject(err) }
  })
}).then((data) => {
  // 请求成功
}, err => {
  // 请求失败
  console.error(err)
})

/* -------------------------------- */
new Promise((resolve, reject) => {
  reject('error')
}).then(success => {

}, err => {
  console.error(err)
})

提示

由于 then 和 Promise.prototype.catch() 方法都会返回 promise,所以它们可以被链式调用——这同时也是一种被称为复合(composition) 的操作。

状态

  • pending

    等待状态,比如正在进行网络请求或定时器没到时间。

  • fulfill

    满足状态,当我们主动调用了 resolve() 时,就处于该状态,并且会回调 then()。

  • reject

    拒绝状态,当我们主动调用了 reject() 时,就处于该状态,并且会回调 catch()。

链式调用

其实在上面的例子中就已经使用了链式调用。

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('aaa')
  }, 1000)
}).then(data => {
  console.log(data, '第一次处理aaa')

  new Promise(resolve => {
    resolve(data + '123')
  })
}).then(data => {
  console.log(data, '第二次处理')
})

在上面的代码中,我们在某些 Promise 中没有进行异步操作,而只是单纯的处理数据而已,因此,我们可以直接使用 Promise.resolve()。修改如下:

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('aaa')
  }, 1000)
}).then(data => {
  console.log(data, '第一次处理aaa')

  return Promise.resolve(data + '123')
}).then(data => {
  console.log(data, '第二次处理')
})

但是,我们还可以把上面的代码再次进行优化,省略 Promise.resolve(data + '123'),直接 return:

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('aaa')
  }, 1000)
}).then(data => {
  console.log(data, '第一次处理aaa')

  return data + '1233'
}).then(data => {
  console.log(data, '第二次处理')
})

但是如果上面的代码执行过程中发生错误呢,这时,我们可以使用 catch():

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('aaa')
  }, 1000)
}).then(data => {
  console.log(data, '第一次处理aaa')

  return new Promise((resolve, reject) => {
      reject('错误')
  })
}).then(data => {
  console.log(data, '第二次处理')
}).catch(err => {
    console.error(err)
})

简写如下:

new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('aaa')
  }, 1000)
}).then(data => {
  console.log(data, '第一次处理aaa')

  return Promise.reject('error!!')
}).then(data => {
  console.log(data, '第二次处理')
}).catch(err => {
  console.error(err)
})

/* ---------------- 使用 throw 抛出异常 --------------- */
new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('aaa')
  }, 1000)
}).then(data => {
  console.log(data, '第一次处理aaa')

  throw 'the exception is found'
}).then(data => {
  console.log(data, '第二次处理')
}).catch(err => {
  console.error(err)
})

all()

在某种情况下,我们可能同时发出多个请求,而且需要等到这些请求全部成功后才能进行某种处理。普通的写法如下:

let isResult1 = false
let isResult2 = false

$.ajax({
  url: '',
  success: function(data) {
    isResult1 = true
    handlerResult()
  }
})

$.ajax({
  url: '',
  success: function(data) {
    isResult2 = true
    handlerResult()
  }
})

function handlerResult() {
  if (isResult1 && isResult2) {
    // ...
  }
}

我们可以使用 Promise 提供的 all() 方法,该方法传入一个可迭代对象(即数组等可以循环的对象),它会自动监听请求状态:

Promise.all([
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({name: 'kk', age: 12})
    }, 1000)
  }),
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('xxx')
    }, 3000)
  })
]).then(results => {
  // 数组
  console.log(results)
})

any()

Promise.any() 方法接收一个可迭代对象(如数组),它会返回一个新的 Promise,该 Promise 在可迭代对象中的任意一个 Promise 成功时就会被解析,并返回第一个成功的结果。如果所有的 Promise 都失败,则返回一个 AggregateError 错误。

Promise.any([
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第一个成功')
    }, 1000)
  }),
  new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('第二个失败')
    }, 2000)
  }),
  new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('第三个成功')
    }, 3000)
  })
]).then(result => {
  console.log(result) // 第一个成功
}).catch(err => {
  console.error(err)
})
想要编辑此页?
上次更新: 2025/6/5 23:39
贡献者: Junfeng Dai
←globalThisasync-await→
[ 纸上得来终觉浅绝知此事要躬行 ]
Copyright © 2021-present Junfeng Dai
蜀ICP备2021009537号