Jacky's blog Jacky's blog
首页
  • 编码专题
  • 深入浅出 Vite
  • 深入浅出 babel
  • 快速上手API
  • 深入浅出 react
  • Node

    • code-notebook
  • 状态管理

    • redux
  • 前端工程化

    • Wepack
  • React源码

    • React源码
  • 组件库封装

    • 组件库
  • 开发工具

    • Vscode 插件
  • 项目展示
  • 案例中心 (opens new window)
  • First Project
  • 基础算法题
  • 链表题
  • 动态规划
  • 双指针
  • 递归
  • 数据结构
  • 前端学习计划 (opens new window)
  • 技术随笔
  • 转载文章
  • 包管理工具
  • 前端学习周报
  • VSCode插件
  • Promise 专题
  • 函数技巧
  • React 专题
  • 配置文件

    • TSCONFIG-配置 (opens new window)
    • NGINX-配置 (opens new window)
    • 正则规则查询手册 (opens new window)
    • Lint 配置 (opens new window)
  • 教程

    • GIT-教程
    • NPM SCRIPTS-工作流 (opens new window)
    • DOCKER-教程 (opens new window)
    • LERNA-教程 (opens new window)
    • GIT-常用操作整理 (opens new window)
  • VSCode

    • LAUNCH.JSON (opens new window)
  • 指令

    • NPM 指令 (opens new window)
    • NVM 指令 (opens new window)
    • Nginx 指令 (opens new window)
    • YARN 指令 (opens new window)
    • PNPM 指令 (opens new window)
  • 库

    • FS-EXTRA 库 (opens new window)
    • NODE 库-PATH (opens new window)
  • 永远的神

    • 魔法师卡颂-自顶向下学 React 源码 (opens new window)
    • 全栈潇晨 (opens new window)
    • 博客-程序员山月-Daily (opens new window)
    • 淘系前端:冴羽 (opens new window)
  • 系列文章

    • 《图解HTTP》 (opens new window)
    • 《ES6标准入门》 (opens new window)
    • 《现代JavaScript教程》 (opens new window)
    • 《深入浅出Webpack》 (opens new window)
    • VSCode 插件系列:小茗同学 (opens new window)
    • JEST 教程 (opens new window)
    • 前端精读周刊:各种精读系列 (opens new window)
    • 一文吃透系列 (opens new window)
    • 图解 REACT 原理 (opens new window)
  • 实用网站

    • MDN (opens new window)
    • CAN I USE (opens new window)
    • TYPESCRIPT-ESLint-RULES (opens new window)
    • ESLint-RULES (opens new window)
    • FRONT-END TREND (opens new window)
    • NPM TREND (opens new window)
    • 在线分析 Node 依赖 (opens new window)
    • FIND NPM (opens new window)
    • CODE PEN (opens new window)
    • 印记中文 (opens new window)
    • TOOL.LU (opens new window)
    • 阮一峰-网道 (opens new window)
    • DIGITAL OCEAN (opens new window)
    • DEVDOCS.IO (opens new window)
    • JOI (opens new window)
  • 算法

    • 小浩算法 (opens new window)
    • LABULADONG 的算法小抄 (opens new window)
    • 力扣 SOLUTION (opens new window)
    • HACKER RANK (opens new window)
    • 代码随想录 (opens new window)
  • 博客系列

    • 美团大佬 (opens new window)
    • 蜡笔小伟 (opens new window)
    • 优秀博客1 (opens new window)
    • 优秀博客2-umi (opens new window)
    • 优质博客 (opens new window)
  • CSS

    • CSS-EASING 库 (opens new window)
    • ROUGH.JS (opens new window)
    • CSS 网站收集
    • UNOCSS (opens new window)
  • 前端

    • PROMISE (opens new window)
    • UNDERSCORE.JS (opens new window)
    • study with BGM (opens new window)
    • nginx【B站视频】 (opens new window)
    • 机器学习
    • Js基础
  • 掘金已购课程

    • 前端自动化测试精讲 (opens new window)
    • 深入浅出 Vite (opens new window)
    • 现代 Web 布局 (opens new window)
    • 前端算法与数据结构 (opens new window)
    • 基于 Vite 的 SSG 框架开发实战 (opens new window)
    • SSR 实战:官网开发指南 (opens new window)
    • WebGL 入门与实践 (opens new window)
    • 玩转 CSS 的艺术之美 (opens new window)
    • 前端调试通关秘籍 (opens new window)
    • React 进阶实践指南 (opens new window)
    • TypeScript 全面进阶指南 (opens new window)
    • 前端缓存技术与方案解析 (opens new window)
    • npm scripts 前端工作流 (opens new window)
    • Webpack5 核心原理与应用实践 (opens new window)
  • 购物车

    • 张鑫旭-技术写作指南 (opens new window)
    • 深入剖析 Node.js 底层原理 (opens new window)
    • 前端开发者的现代 C++ 课 (opens new window)
    • 从前端到全栈 (opens new window)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Jacky Wang

行到水穷处,坐看云起时
首页
  • 编码专题
  • 深入浅出 Vite
  • 深入浅出 babel
  • 快速上手API
  • 深入浅出 react
  • Node

    • code-notebook
  • 状态管理

    • redux
  • 前端工程化

    • Wepack
  • React源码

    • React源码
  • 组件库封装

    • 组件库
  • 开发工具

    • Vscode 插件
  • 项目展示
  • 案例中心 (opens new window)
  • First Project
  • 基础算法题
  • 链表题
  • 动态规划
  • 双指针
  • 递归
  • 数据结构
  • 前端学习计划 (opens new window)
  • 技术随笔
  • 转载文章
  • 包管理工具
  • 前端学习周报
  • VSCode插件
  • Promise 专题
  • 函数技巧
  • React 专题
  • 配置文件

    • TSCONFIG-配置 (opens new window)
    • NGINX-配置 (opens new window)
    • 正则规则查询手册 (opens new window)
    • Lint 配置 (opens new window)
  • 教程

    • GIT-教程
    • NPM SCRIPTS-工作流 (opens new window)
    • DOCKER-教程 (opens new window)
    • LERNA-教程 (opens new window)
    • GIT-常用操作整理 (opens new window)
  • VSCode

    • LAUNCH.JSON (opens new window)
  • 指令

    • NPM 指令 (opens new window)
    • NVM 指令 (opens new window)
    • Nginx 指令 (opens new window)
    • YARN 指令 (opens new window)
    • PNPM 指令 (opens new window)
  • 库

    • FS-EXTRA 库 (opens new window)
    • NODE 库-PATH (opens new window)
  • 永远的神

    • 魔法师卡颂-自顶向下学 React 源码 (opens new window)
    • 全栈潇晨 (opens new window)
    • 博客-程序员山月-Daily (opens new window)
    • 淘系前端:冴羽 (opens new window)
  • 系列文章

    • 《图解HTTP》 (opens new window)
    • 《ES6标准入门》 (opens new window)
    • 《现代JavaScript教程》 (opens new window)
    • 《深入浅出Webpack》 (opens new window)
    • VSCode 插件系列:小茗同学 (opens new window)
    • JEST 教程 (opens new window)
    • 前端精读周刊:各种精读系列 (opens new window)
    • 一文吃透系列 (opens new window)
    • 图解 REACT 原理 (opens new window)
  • 实用网站

    • MDN (opens new window)
    • CAN I USE (opens new window)
    • TYPESCRIPT-ESLint-RULES (opens new window)
    • ESLint-RULES (opens new window)
    • FRONT-END TREND (opens new window)
    • NPM TREND (opens new window)
    • 在线分析 Node 依赖 (opens new window)
    • FIND NPM (opens new window)
    • CODE PEN (opens new window)
    • 印记中文 (opens new window)
    • TOOL.LU (opens new window)
    • 阮一峰-网道 (opens new window)
    • DIGITAL OCEAN (opens new window)
    • DEVDOCS.IO (opens new window)
    • JOI (opens new window)
  • 算法

    • 小浩算法 (opens new window)
    • LABULADONG 的算法小抄 (opens new window)
    • 力扣 SOLUTION (opens new window)
    • HACKER RANK (opens new window)
    • 代码随想录 (opens new window)
  • 博客系列

    • 美团大佬 (opens new window)
    • 蜡笔小伟 (opens new window)
    • 优秀博客1 (opens new window)
    • 优秀博客2-umi (opens new window)
    • 优质博客 (opens new window)
  • CSS

    • CSS-EASING 库 (opens new window)
    • ROUGH.JS (opens new window)
    • CSS 网站收集
    • UNOCSS (opens new window)
  • 前端

    • PROMISE (opens new window)
    • UNDERSCORE.JS (opens new window)
    • study with BGM (opens new window)
    • nginx【B站视频】 (opens new window)
    • 机器学习
    • Js基础
  • 掘金已购课程

    • 前端自动化测试精讲 (opens new window)
    • 深入浅出 Vite (opens new window)
    • 现代 Web 布局 (opens new window)
    • 前端算法与数据结构 (opens new window)
    • 基于 Vite 的 SSG 框架开发实战 (opens new window)
    • SSR 实战:官网开发指南 (opens new window)
    • WebGL 入门与实践 (opens new window)
    • 玩转 CSS 的艺术之美 (opens new window)
    • 前端调试通关秘籍 (opens new window)
    • React 进阶实践指南 (opens new window)
    • TypeScript 全面进阶指南 (opens new window)
    • 前端缓存技术与方案解析 (opens new window)
    • npm scripts 前端工作流 (opens new window)
    • Webpack5 核心原理与应用实践 (opens new window)
  • 购物车

    • 张鑫旭-技术写作指南 (opens new window)
    • 深入剖析 Node.js 底层原理 (opens new window)
    • 前端开发者的现代 C++ 课 (opens new window)
    • 从前端到全栈 (opens new window)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 编码专题

    • 00.React-目录
    • 10.React-组件-组件封装
    • 11.React-hooks-自定义钩子
    • 21.函数技巧 - 函数式编程之 compose 函数
    • 22.函数技巧-tapable钩子
    • 23.函数技巧-koa源码
    • 30.Promise系列-目录
    • 31.Promise-深入Promise原理
    • 32.Promise-指令式Promise改造
    • 32.promise-梳理 Promise 错误处理
    • 34.promise-竞态问题
    • 35.Promise-如何处理异步数组
      • 0.前言
      • 1.Promise 思考
        • 如何取数组数据?
        • 异步列表的串行执行
        • 异步列表的并行执行
      • 2. 综合案例-异步 sum 累加
  • 深入浅出 Vite

  • 快速上手 API

  • 深入浅出Babel

  • 深入浅出 React

  • 百问掘金
  • 编码专题
wangjiasheng
2022-10-11
目录

35.Promise-如何处理异步数组

# 0.前言

本章节核心工作就是:梳理异步编码写法。

# 1.Promise 思考

# 如何取数组数据?

对于大部分的前端面试题处理都是异步执行列表,因此第一步思考的是如何处理这个数组?

一般而言,异步执行列表中的元素有两种类型:普通数据及Promise 对象。

// 1. 纯数据数组
let promiseLit = [1, 2, 3, 4, 5];
// 2. Promise任务 和 数据混合数组
let promiseLit = [Promise.resolve(1), 2, 3, 4, 5];
1
2
3
4

特别注意,在上述数组中的 Promise 的异步事件,也是同步执行代码,如果立即打印:

let promiseList = [Promise.resolve(1),Promise.reject(2),Promise任务];
// 直接打印结果
[ Promise {<fulfilled>: 1}, Promise {<rejected>: 1},Promise{<pending>}];
1
2
3

因此,需要使用 Promise.resolve 取出数据

promiseList.map((p) =>
  Promise.resolve(p).then((result) => console.log(result)),
);
1
2
3

# 异步列表的串行执行

串行的核心:就是在上一层的结果的基础上继续进行某种操作,如果不使用 promise,而使用 callback 方式,从结构上来讲就是嵌套类型。

# 写法一:for 循环 + 函数包装

基本结构:

async function xxx(arr) {
  let res;
  for (let i = 0; i < arr.length; i +) {
    if (i === 0) {
      // 处理初始值
    } else {
      res = await + /* promise异步任务 */
    }
    return res;
  }
}
1
2
3
4
5
6
7
8
9
10
11

因为 async 和 await 这种方式具有传染性,因此需要在外部包装一个函数。

# 写法二:构建 promise 的 .then 串

伪代码如下:

arr.slice(1).reduce((pre, cur) => {
  /* 获取 cur 的异步结果 */
  Promise.resolve(cur).then(curValue => ......);
  /* 获取 pre 的异步结果 */
  pre.then(result =>.....);
  /* 当两个异步任务都完成后,将各自的结果传入一个异步任务并返回*/
  return asyncAdd(result, curValue);
}, Promise.resolve(arr[0]);
1
2
3
4
5
6
7
8

# 异步列表的并行执行

按照题型分为:合并一个结果及数组结果。

# 方案一:使用分组的方式实现并行

  1. 将数组分组:使用 chunk

    function chunk(list, size) {
      const res = [];
      for (let i = 0; i < list.length; i++) {
        const index = Math.floor(i / size);
        res[index] = res[index] || [];
        res[index].push(list[i]);
      }
      return res;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  2. 将数组分组:chunk(arr,2)

    结果为:[1,2,3,4,5,6,7]=>[[1,2],[3,4],[5,6],[7]]

    使用 arr.map 构造 Promise 队列,即

    [Promise<pending,1+2>,Promise<pending,3+4>,Promise<pending,5+6>,Promise<pending,7>
    
    1
  3. 偷懒了:直接使用 Promise.all 进行串行转化为 数组结构。

    Promise.all([xxx,xxx,xxx]).then(result=>....);
    
    1
  4. 最后递归调用,并设置截止条件:

    // 最后结果为: [[15]]
    if(arr.length) === 1 return arr[0];
    
    1
    2

# 2. 综合案例-异步 sum 累加

请实现一个 sum 函数,接收一个数组 arr 进行累加,并且只能使用 add 异步方法 add 函数已实现,模拟异步请求后端返回一个相加后的值

sum([1, 2, 3, 4, 5]).then((o) => console.log(o));

// 异步相加函数
function add(a, b) {
  return Promise.resolve(a + b);
}
1
2
3
4
5
6
  • 串行实现

    • 使用 reduce 构建执行串

      function sum(arr) {
        return arr.reduce((pre, cur) => {
          return Promise.resolve(pre).then((preRes) => add(preRes, cur));
        });
      }
      
      1
      2
      3
      4
      5

      改进版,使用 .slice(1).reduce 技巧

      function sum(arr) {
        return arr.slice(1).reduce((pre, cur) => {
          return pre.then((preRes) => add(preRes, cur));
        }, Promise.resolve(arr[0]));
      }
      
      1
      2
      3
      4
      5
    • 使用 await + async 实现

      async function sum(arr) {
        let res = arr[0]; // 使用 res 维护一个持续累加的变量
        for (let i = 1; i < arr.length; i++) {
          res = await add(res, arr[i]);
        }
      }
      
      1
      2
      3
      4
      5
      6

      存在的风险是,await 可能会被错误拦截,需要使用 try...catch 去捕获错误。

  • 并行实现

    function sum(arr: any[]) {
      // 递归截止条件,结果为: [[ 15 ]]
      if (arr.length === 1) return arr[0];
      // 将 arr 封装为 promiseTask
      const promiseTasks = chunk(arr, 2).map(([x, y]) => {
        return y === undefined ? x : add(x, y);
      }); // 结果为:[add1,add2,add3,x]
      return Promise.all(promiseTasks).then((list) => sum(list));
    }
    
    /* 分组函数*/
    function chunk(list, size = 2) {
      const res = [];
      for (let i = 0; i < list.length; i++) {
        const index = Math.floor(i / size);
        res[index] = res[index] || [];
        res[index].push(list[i]);
      }
      return res;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
编辑 (opens new window)
上次更新: 2023/10/02, 17:10:00
34.promise-竞态问题
00-目录大纲

← 34.promise-竞态问题 00-目录大纲→

最近更新
01
如何理解浏览器的 user agent 用户代理的含义?
11-05
02
浏览器事件循环机制
10-31
03
浏览器页面渲染机制【2023】
10-15
更多文章>
Theme by Vdoing | Copyright © 2020-2023
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式