1export const useHook = (
 2  values: number[]
 3) => {
 4  const colorScale = useMemo(() => {
 5    const min = Math.min(...values);
 6    const max = Math.max(...values);
 7
 8    return ...;
 9  }, [values]);
10
11  return ...;
12};

问题描述 Link to heading

1Math.max(...Array(1000000).fill(1))
2
3/**
4VM746:1 Uncaught RangeError: Maximum call stack size exceeded
5    at Math.max (<anonymous>)
6    at <anonymous>:1:6
7*/

在使用超长数组进行 Math.max 运算时,报错 Maximum call stack size exceeded

原因分析 Link to heading

原因很简单噻,看一看 Javascript 的 Runtime Environment:

js-runtime-environment

Call Stack,也就是调用栈长度是有限的。你可以调用这段代码看看你的调用栈长度:

 1var i = 0;
 2function inc() {
 3  i++;
 4  inc();
 5}
 6    
 7try {
 8  inc();
 9}
10catch(e) {
11  // The StackOverflow sandbox adds one frame that is not being counted by this code
12  // Incrementing once manually
13  i++;
14  console.log('Maximum stack size is', i, 'in your current browser');
15}
16
17// Maximum stack size is 11010 in your current browser

我在 Chrome 中运行结果是 11010,通过二分法获得 Math. Max 可以最长调用的数组长度为 110083,差不多是 11010 的 10 倍(这潜在说明了一个函数调用所需要 Frame 在没有传参的时候大概是 10 个 number 类型长度) 。

U math-max-stack-size

解决方案 Link to heading

使用自定义 min/max 方法,变 spread 为 loop。

 1function arrayMin(arr: number[]) {
 2  var len = arr.length,
 3    min = Infinity;
 4  while (len--) {
 5    if (arr[len] < min) {
 6      min = arr[len];
 7    }
 8  }
 9  return min;
10}
11
12function arrayMax(arr: number[]) {
13  var len = arr.length,
14    max = -Infinity;
15  while (len--) {
16    if (arr[len] > max) {
17      max = arr[len];
18    }
19  }
20  return max;
21}

经测试有用,且没有了展开运算,性能更高效,使用 lodash 等方案也可以。