回顾数组reduce方法的使用

August 21, 2020 ... ☕️ 2 min read

昨天参加面试的时候,在线coding的环节被问到Promise串行操作。对于Promise是比较熟悉的,generator、异步、事件系统的结构和流程等等。但是循环await之后,面试官问还有其他解法吗?如果直接用数组的方法怎么写呢?陷入了沉默,因为常用的map、forEach都属于循环,流程是一样的,这题没答上来。最后问起来,面试官说其实使用reduce也可以,只需要一行代码,你可以下去试试。

reduce?虽然知道这个方法,但是一直以来都比较抗拒,其一是因为操作相对于map/forEach来说比较复杂,二是写在代码里,如果注释不太清楚,会有些困扰。总结来说一个字:菜。

基本语法

arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)

reduce会把累加器(accumulator)应用到数组中的每个元素,返回一个计算后的累加值。

一般用法

1、数值累加或统计

数值累加

const arr = [1, 2, 3];
let result = 0;
for(let index in arr) {
  result += arr[index];
}
// 使用reduce
result = arr.reduce((accum, element) => {
  return accum + element;
}, 0);

统计字母出现的次数

const str = 'abacabbaccadef';
let statistics = str.split('').reduce((sts, element) => {
  if (sts.hasOwnProperty(element)) {
    sts[element]++;
  } else {
    sts[element] = 1;
  }
  return sts;
}, {});
//{a: 5, b: 3, c: 3, d: 1, e: 1, f: 1}

可以看出,初始值决定了第一个参数的类型,以及各个元素将以何种方式迭代。回到上面的题目,如何用reduce顺序执行Promise呢?

reduce顺序执行Promise

异步函数抽象成如下结构

function request(a) {
  return function () {
    return new Promise((resolve, reject) => {
      resolve(a * 3);
    });
  }
}
const p1 = request(1);
const p2 = request(2);
const p3 = request(3);
const arr = [p1, p2, p3];
function sequence(arr) {
  return arr.reduce((promiseChain, currentPromise) => {
    return promiseChain.then((chainedResult) => {
      return currentPromise(chainedResult)
      .then((res) => res);
    })
  }, Promise.resolve());
}

首先要知道,then返回的也是一个Promise对象(否则无法链式调用),所以 return promiseChain.then()返回的还是一个Promise对象,这个对象会作为promiseChain的新值来继续后面的迭代。

如果用普通的遍历来写,会更直观一些

const promiseChain = Promise.resolve();
for (let i in arr) {
  const currentProm = arr[i];
  promiseChain = promiseChain.then((res) => {
    return currentProm(res).then((innerRes) => innerRes)
  });
}

promiseChain这里作为一个执行器使用的,通过每次取得返回的新Promise,来完成顺序执行的目的。

就像正则一样,有些知识可能有其他迂回的办法能解决,但是如果知识面更宽,会带来不一样的思路。

#js#reduce

SideEffect is a blog for front-end web development.
Code by Axiu / rss