js【详解】Promise(含 Promise 的三种状态及其变化,创建 Promise, Promise.all 语法、Promise.all 实战范例、手写 Promise.all)

简介: js【详解】Promise(含 Promise 的三种状态及其变化,创建 Promise, Promise.all 语法、Promise.all 实战范例、手写 Promise.all)

为什么需要使用 Promise ?

传统回调函数的代码层层嵌套,形成回调地狱,难以阅读和维护,为了解决回调地狱的问题,更加优雅地书写复杂的异步任务,诞生了 Promise

什么是 Promise ?

Promise 是一种异步编程的解决方案,本身是一个构造函数

console.log(Promise); // [Function: Promise]

自带resolve,reject,all 等方法,其原型上还有then、catch等方法。

Promise 的三种状态及其变化

  1. pending 进行中,不会触发 then 和 catch 回调函数
  2. resolved / fulfilled 已成功,会触发后续的 then 回调函数
  3. rejected 已失败,会触发后续的 catch 回调函数


Promise 的状态变化如上图所示,不可逆

  • Promise 最初的状态是 pending
  • pending 状态的 Promise 执行 resolve() 后,状态变为 resolved
Promise.resolve(); // Promise 的状态从 pending 变为 resolved

resolved 状态的 Promise 会触发后续的 then 函数,

  • 若 then 函数内没有报错,则返回一个 resolved 状态的 Promise
Promise.resolve().then(() => {}); // 最终 Promise 的状态为 resolved

若 then 函数内报错,则返回一个 rejected 状态的 Promise

Promise.resolve().then(() => {
  throw new Error("then函数出现报错");
}); // 最终 Promise 的状态为 rejected

pending 状态的 Promise 执行 reject() 后,状态变为 rejected

Promise.reject(); // Promise 的状态从 pending 变为 rejected

rejected 状态的 Promise 会触发后续的 catch 函数,

  • 若 catch 函数内没有报错,则返回一个 resolved 状态的 Promise
Promise.reject().catch(() => {}); // 最终 Promise 的状态为 resolved

若 catch 函数内报错,则返回一个 rejected 状态的 Promise

Promise.reject().catch(() => {
  throw new Error("catch函数出现报错");
}); // 最终 Promise 的状态为 rejected

创建 Promise

新创建的 Promise 实例的状态为 pending

// 此时,p1 的状态为 pending
const p1 = new Promise((resolve, reject)=>{
 
})

执行 resolve() ,Promise 实例的状态变为 fulfilled

const p1 = new Promise((resolve, reject) => {
  resolve()
})

执行 reject() ,Promise 实例的状态变为 reject

const p1 = new Promise((resolve, reject) => {
  reject()
})

Promise.all

Promise .all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);
  • p1、p2、p3 都是 Promise 实例,得到的 p 也是Promise 实例
  • Promise .all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
  • p1、p2、p3 的状态都变成 fulfilled, p 的状态才会变成 fulfilled
  • p1、p2、p3 之中有一个被 rejected,p 的状态就变成 rejected
  • p 的 then 函数中得到的是 p1、p2、p3 的返回值组成的一个数组

promise.all 实战范例

import axios from 'axios'

let infoList = []

let id_list = ['1', '2', '3']

let promise_list = []

for (let id of id_list) {
  promise_list.push(axios.get(`http://jsonplaceholder.typicode.com/users/${id}`))
}

Promise.all(promise_list).then((res) => {
  infoList = res.map((item) => item.data)
  console.log(infoList) // 得到预期结果
})

手写 promise.all

function pAll (_promises) {
    return new Promise((resolve, reject) => {
      // Iterable => Array
      const promises = Array.from(_promises)
      // 结果用一个数组维护
      const r = []
      const len = promises.length
      let count = 0
      for (let i = 0; i < len; i++) {
        // Promise.resolve 确保把所有数据都转化为 Promise
        Promise.resolve(promises[i]).then(o => { 
          // 因为 promise 是异步的,保持数组一一对应
          r[i] = o;
  
          // 如果数组中所有 promise 都完成,则返回结果数组
          if (++count === len) {
            resolve(r)
          }
          // 当发生异常时,直接 reject
        }).catch(e => reject(e))
      }
    })
 }

Promise 自测题

此时仅创建了 Promise 对象,没有执行 resolve() 或 reject(),所以状态是 pending

因 setTimeout 是异步任务,内部代码在打印完 p2 后才执行,所以在打印 p2 时,Promise 还没执行 resolve() ,状态是 pending。

打印完 p2 后,setTimeout 内的 resolve() 执行,Promise 的状态变为 resolved

目录
相关文章
|
1月前
|
前端开发 JavaScript
用JavaScript 实现一个简单的 Promise 并打印结果
用 JavaScript 实现一个简单的 Promise 并打印结果
|
1月前
|
JSON 前端开发 JavaScript
在 JavaScript 中,如何使用 Promise 处理异步操作?
通过以上方式,可以使用Promise来有效地处理各种异步操作,使异步代码更加清晰、易读和易于维护,避免了回调地狱的问题,提高了代码的质量和可维护性。
|
18天前
Next.js 实战 (二):搭建 Layouts 基础排版布局
本文介绍了作者在Next.js v15.x版本发布后,对一个旧项目的重构过程。文章详细说明了项目开发规范配置、UI组件库选择(最终选择了Ant-Design)、以及使用Ant Design的Layout组件实现中后台布局的方法。文末展示了布局的初步效果,并提供了GitHub仓库链接供读者参考学习。
Next.js 实战 (二):搭建 Layouts 基础排版布局
|
29天前
|
前端开发
`Promise.allSettled()`方法与`Promise.all()`方法有何不同?
`Promise.allSettled()` 提供了一种更灵活和全面的方式来处理多个 `Promise`,使得我们能够更好地应对各种异步操作的情况,尤其是需要详细了解每个 `Promise` 结果的场景。
|
13天前
|
存储 网络架构
Next.js 实战 (四):i18n 国际化的最优方案实践
这篇文章介绍了Next.js国际化方案,作者对比了网上常见的方案并提出了自己的需求:不破坏应用程序的目录结构和路由。文章推荐使用next-intl库来实现国际化,并提供了详细的安装步骤和代码示例。作者实现了国际化切换时不改变路由,并把当前语言的key存储到浏览器cookie中,使得刷新浏览器后语言不会失效。最后,文章总结了这种国际化方案的优势,并提供Github仓库链接供读者参考。
|
13天前
Next.js 实战 (三):优雅的实现暗黑主题模式
这篇文章介绍了在Next.js中实现暗黑模式的具体步骤。首先,需要安装next-themes库。然后,在/components/ThemeProvider/index.tsx文件中新增ThemeProvider组件,并在/app/layout.tsx文件中注入该组件。如果想要加入过渡动画,可以修改代码实现主题切换时的动画效果。最后,需要在需要的位置引入ThemeModeButton组件,实现暗黑模式的切换。
|
29天前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
29 2
|
1月前
|
前端开发 JavaScript Java
一文带你了解和使用js中的Promise
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,正向全栈进发。如果我的文章对你有帮助,请关注我,将持续更新更多优质内容!🎉🎉🎉
21 0
一文带你了解和使用js中的Promise
|
1月前
|
JSON 前端开发 JavaScript
浅谈JavaScript中的Promise、Async和Await
【10月更文挑战第30天】Promise、Async和Await是JavaScript中强大的异步编程工具,它们各自具有独特的优势和适用场景,开发者可以根据具体的项目需求和代码风格选择合适的方式来处理异步操作,从而编写出更加高效、可读和易于维护的JavaScript代码。
33 1
|
1月前
|
前端开发 JavaScript
JavaScript新纪元:ES6+特性深度解析与实战应用
【10月更文挑战第29天】本文深入解析ES6+的核心特性,包括箭头函数、模板字符串、解构赋值、Promise、模块化和类等,结合实战应用,展示如何利用这些新特性编写更加高效和优雅的代码。
45 0