React 和 Javascript 优化技术

更新日期: 2024-02-27阅读: 263标签: 优化

当我们开始一个项目时,我们往往会关注可扩展性、可用性、可用性、安全性等问题。但是,随着应用程序的增长,我们可能会发现其速度和性能有所下降。通常只有在这个时候,我们才会意识到优化的必要性。

在本文中,我们将介绍一些最常用的代码优化技术,这些技术可以在任何应用程序中实现;我们还将使用 JavaScript 和 React 编写的示例代码展示优化技术。我们将介绍以下技术:

防抖
节流
记忆化
纯组件
懒加载
虚拟化(或窗口化)
错误边界
内联函数

还有更多可用的技术,但在本文中,我们将重点讨论已提及的技术。


防抖

防抖是一种编程技术,用于优化消耗大量执行时间的函数的处理。这种技术可以防止这些函数在不受控制的情况下重复执行,从而有助于提高应用程序的性能。

在应用程序必须对某些用户操作做出响应的情况下,我们往往无法避免重复执行某些函数。例如,诸如 mousemove 或 window.resize 等事件可能会通过简单的鼠标移动或浏览器窗口大小调整触发对这些函数的数百次调用。在这种情况下,我们就需要使用防抖等技术来限制这些调用,并解决这些事件或函数可能导致的性能问题。

防抖的操作非常简单。它包括创建一个函数,作为拦截器限制对我们要优化的回调函数的调用。该函数至少有两个参数:时间和回调。时间参数用于向 Debounce 指示该函数在被调用前应等待多长时间,而回调参数则是以该时间限制为条件的函数。一旦创建了控制机制,防抖函数就会返回一个新的优化函数,用来替代原来的函数。

值得注意的是,在防抖动过程中,如果在定义的时间窗口内多次调用回调函数,那么只有最后一次调用才会被考虑执行,之前的调用将被丢弃。此外,每次发生调用时,时间窗口也会更新。例如,如果我们将时间定义为 2 秒,那么在防抖函数中定义的回调将只在 2 秒后执行。如果在时间窗口内发生多次调用,时间将在同一时段内更新,一旦达到所定义的时间,将只执行进入防抖函数的最后一个函数。

下面是一个如何使用 JavaScript 在代码中实现防抖跳的简单示例:

// Example 1

const debounce = (callback, time = 300) => {
let timer;

return () => {
clearTimeout(timer);
timer = setTimeout(callback, time);
};
};

在这个简化版本中,防抖函数会返回另一个处理防抖的函数。返回的函数会清除定时器变量中之前创建的超时,并以收到的回调作为参数设置新的超时。每次执行新的防抖函数时,它都会访问同一个定时器变量、清除它并替换每次的超时。

这样,我们就创建了防抖,使用方法如下:

// Example 2

// this is the function we want to debounce
const showMessage = () => console.log("Hello Message");

// this is the debounced function with 1 second of delay
const debouncedMessage = debounce(showMessage, 1000);

// we are calling it 10000 times in this loop
for (let i = 0; i < 10000; i++) {
setTimeout(debouncedMessage, i);
}

在本例中,debouncedMessage 函数将在 for 循环中被调用 10,000 次。不过,由于去抖的原因,消息只会显示一次,而不是 10,000 次。


节流

节流技术与防抖技术类似,都用于限制函数调用的频率。不同的是,节流不会在每次调用函数时都清除计时器,而是使用暂停条件来避免创建新的计时器。换句话说,当函数被调用时,它不会等到最后一次调用才执行,而是只有在进入禁用暂停的时间间隔时才会调用函数。

让我们看一个例子来更好地理解它:

// Example 3

const throttle = (callback, time = 300) => {
let pause = false;


return () => {
if (pause) return;
pause = true;
callback();
setTimeout(() => {
pause = false;
}, time);
};
};

在上面的示例中,我们可以看到,与 debounce 不同的是,我们现在有了一个暂停变量,而不是计时器。我们可以看到,它现在会检查暂停是否为 true 才返回,这基本上是为了阻止其他代码的执行,是一个转义词。如果在该条件下执行没有中断,我们要做的就是激活暂停,这样,对该函数的后续调用将不会执行,因为暂停将被激活。然后,我们调用回调函数,最后关闭节流过程,留下一个 setTimeout,以便在我们定义的时间到时禁用暂停。

正如我们前面解释的那样,使用节流的结果是,我们将限制函数的调用,但只要这些函数继续被调用,就会每隔一定时间执行一次。而 "debouncing "则是等待最后一次调用,只执行一次函数。

为了更好地理解,我们来看下面的示例:

// Example 4

// this is the function we want to throttle
const showMessage = () => console.log("Hello Message");

// this is the throttled function with 1 second of delay
const throttledMessage = throttle(showMessage, 1000);

// we are calling it 10000 times in this loop
for (let i = 0; i < 10000; i++) {
setTimeout(throttledMessage, i);
}

在防抖的情况下,信息只显示一次,因为在每次执行时,超时都会延长,直到最后一次调用持续了 10 秒(10,000 毫秒)。相比之下,对于节流,由于执行时会暂停,因此信息会显示 10 次,每秒显示一次(1000 毫秒)。如您所见,两种技术的目标相同,但代码和行为略有不同。这种细微差别允许我们根据具体情况选择一种机制或另一种机制。因此,了解这两种技术非常重要,这样才能知道何时执行其中一种,从而正确优化我们的代码。


记忆化(Memoization)

记忆化是一种将函数结果存储在内存空间中以便日后检索的技术。这样做是为了避免每次使用相同参数调用函数时都要重新计算结果。这种技术适用于消耗大量资源的函数。在这种情况下,memoization 可以提高性能和获取结果的速度。

在 React 中也可以使用这种技术,我们可以利用 React 中的以下 memoization 功能:

反应备忘录
使用备忘录
useCallback

不过,在解释如何在 React 中使用这些功能之前,我们先以计算一个数字的阶乘的算法为例,具体实现如下:

// Example 5

const getFactorial = (n) => {
if (n === 1 || n === 0) return 1;
return n * getFactorial(n - 1);
};

乍一看,这种算法很简单。然而,作为一个递归函数,我们在向它传递非常大的数字时必须小心谨慎,因为根据我们提供的值,这个函数的处理成本可能会非常高。正如你可能知道的,一个数字的阶乘只是其前代数的递归乘法,直到达到 1,其公式如下:n!

例如,如果我们要计算 6 的阶乘,可以这样计算:6! = 6 - 5 - 4 - 3 - 2 - 1.这种算法的问题在于,许多乘法运算只需进行一次,然后将结果保存在查找表或对象中。这样,当我们需要再次获得这些值时,就不必再重新计算了。将此函数记忆化的一种方法是这样的:

// Example 6

const memoize = fn => {
const cache = new Map();
return (...args) => {
const key = args.join("-");
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
// you can add a console.log(cache) here to see how cache is being filled.
return result;
};
};

const getFactorial = memoize(n => {
if (n === 1 || n === 0) return 1;
return n * getFactorial(n - 1);
});

// it runs 100 times
getFactorial(100);

// all values below 100 were memoized previously, so it runs just once
getFactorial(99);

在本例中,首先定义了 amemoize 函数,该函数将一个函数作为参数,并返回一个将原始函数的结果 memoize 的新函数。这个新函数使用 Map 对象来缓存之前计算的结果。当使用某些参数调用 memoize 函数时,它会首先检查缓存中是否已经存储了这些参数的结果。如果是,则返回已存储的结果。如果没有,则通过调用带有这些参数的原始函数来计算结果,将结果存储在缓存中并返回。

然后,将 getFactorial 函数传递给 memoize 函数,并将结果赋值给一个新变量。现在,getFactorial 的 memoize 版本可以像其他函数一样被调用,但会将之前的结果存储在缓存中,从而提高了重复计算的效率。

换句话说,当我们计算 100 的阶乘时,函数将运行 100 次。但此时,我们已将所有计算结果存储在缓存对象中。因此,当我们以相同的值或低于 100 的值再次运行函数时,将不再需要重新计算所有内容,而是从我们创建的缓存对象中获取其值;因此,函数将只执行一次。

通过这种方式,我们对该函数进行了优化,避免了重新计算,提高了响应速度。总之,memoization 是一种优化组件的好技术。这也是使用优化技术的最大优势之一。

React.memo

这是一个非常有用的工具,当组件接收到的道具没有变化时,它可以避免不必要的组件渲染。React.memo 的目的是提高应用程序的性能。不过,需要注意的是,React.memo 不会阻止由状态或上下文(React.Context)更新引起的组件渲染,因为它只会考虑道具以避免重新渲染。

使用 React.memo 的实现非常简单。下面是一个如何使用它的示例:

// Example 7

import { memo } from "react";
import { MyComponent } from "./MyComponent";

export const App = () => {
// using a component
const MemoizedComponent = memo(MyComponent);

// using a function expression
const MemoizedComponent2 = memo(function ({ data }) {
return <div>Some interesting {data}</div>;
});

// using an arrow function
const MemoizedComponent3 = memo(({ data }) => {
return <div>Some interesting {data}</div>;
});

const someDataPassedAsProp = {};

return <MemoizedComponent data={someDataPassedAsProp} />;
};

这样,只要道具值长期保持不变,组件就不会被重新渲染。这对于拥有大量子组件的应用程序或道具不经常变化的情况尤其有用。通过使用这种方法,可以避免不必要的更新,并提高应用程序的性能。

React.useMemo

通过这个钩子,我们可以在组件渲染之间缓存代价高昂的函数结果,只有当函数的依赖关系发生变化时才重新执行该函数。但要注意的是,这个钩子只能在组件或其他钩子中使用,而不能在循环或条件中使用。

为了理解它是如何工作的,让我们以 expensiveCalculationFn 函数为例,该函数理论上需要执行一系列复杂而昂贵的计算。在我们的组件中,我们可以使用 Memo 来防止它在每次组件呈现时都被执行,从而降低应用程序的运行速度。这样,钩子将返回上次缓存的值,只有在依赖关系发生变化时才更新该值。

下面是一个如何在组件中使用 useMemo 的示例:

// Example 8

import { useMemo, useState } from "react";

const expensiveCalculationFn = (a, b, c) => {
// Let's say this function does an expensive calculation
return a*b*c;
};

export const MyComponent = (props) => {
const { a, b, c } = props;


// only if its dependencies have changed.
const result = useMemo(() => expensiveCalculationFn(a,b,c), [
props
]);

return <h1>{result}</h1>;
};

在本示例中,我们使用了 useMemo 来避免在每次组件呈现时执行昂贵的 CalculationFn。如果依赖关系(本例中为道具)没有发生变化,钩子将返回上次缓存的值。此外,建议使用 useMemo 的函数应为纯函数。

如果您想了解有关此钩子的更多信息,建议查看官方文档,其中包含多个用例,以便更好地了解其功能和在不同情况下的适用性。

请注意,useMemo 并不是用于记忆化的通用 javascript 函数,它只是 React 中用于记忆化的一个内置钩子,而且只建议在少数情况下使用,您可以在此阅读更多相关信息

React.useCallback

useCallback 钩子与前一个钩子非常相似,但不同之处在于,这个钩子缓存的是函数定义,而不是函数执行后的结果值。只有当所定义的依赖关系的值发生变化时,才会更新该钩子。值得注意的是,useCallback 并不执行函数,它只是保存和更新函数的定义,以便我们稍后执行。相比之下,React.useMemo 会执行函数,只在缓存中保存和更新函数的结果值。

例如,这个钩子可以用来缓存作为道具传递给子组件的回调,我们希望避免因父组件的渲染而重新渲染这些回调。通过缓存函数引用,并将回调缓存起来,在不更新的情况下,它将保持不变,因此,如果我们的子组件使用 React.memo 进行封装,由于函数没有变化,它不会触发将其作为道具传递的组件的渲染,从而保持其先前的引用。为了了解如何使用 useCallback,我们将优化以下组件:

// Example 9

import { useEffect, useState} from "react";

// this is our child component we want to optimize
const ChildComponent = ({ callback }) => {
console.log("Child was rendered...");
return <button onClick={callback}>Click me!</button>;
};

export const MyComponent = (props) => {
// here we have some states and variables.
const [color, setColor] = useState("#ff22ff");
const [otherState, setOtherState] = useState(false);
const otherVariables = "other variables...";

// this is our callback we want to cache.
const callbackFn = () => {
console.log("Hello, you clicked!");
};

// this is for trigger a re-render by updating state.
useEffect(() => {
setTimeout(() => {
setColor("#00ddd2");
}, 3000);
}, []);

// this is our child component, with the callback passed as prop.
return <ChildComponent callback={callbackFn} />;
};

在这里,我们有一个普通的组件,没有经过优化,它有一些状态和变量,还渲染了一个接收函数 callbackFn 作为道具的子组件。在这种情况下,每次我们更新组件的状态时,默认情况下,我们的子组件都会重新渲染。如果我们想避免子组件重新渲染,就需要将其封装在 React.memo 中。您可能还记得,如果组件的道具没有变化,React.memo 就会避免组件的重新渲染。因此,让我们开始吧:

// Example 10

import { useEffect, useState, memo } from "react";

// this is our child component we want to optimize
const ChildComponent = memo(({ callback }) => {
console.log("Child was rendered...");
return <button onClick={callback}>Click me!</button>;
});

export const MyComponent = (props) => {
// here we have some states and variables.
const [color, setColor] = useState("#ff22ff");
const [otherState, setOtherState] = useState(false);
const otherVariables = "other variables...";

// this is our callback we want to cache.
const callbackFn = () => {
console.log("Hello, you clicked!");
};

// this is for trigger a re-render by updating state.
useEffect(() => {
setTimeout(() => {
setColor("#00ddd2");
}, 3000);
}, []);

// this is our child component, with the callback passed as prop.
return <ChildComponent callback={callbackFn} />;
};

如您所见,我们现在已经使用 React.memo 缓存了我们的组件。不过,我们还没有完全解决这个问题。我们传递给 ChildComponent 的 MyComponent 内部的函数实际上是一个引用,因此每次 MyComponent 更新时,该函数的引用也会更新。为了防止这种情况在 ChildComponent 中造成不必要的重新呈现,我们可以使用 useCallback。通过使用 useCallback,只要函数的依赖关系保持不变,函数就会保留其定义和引用。这将防止 ChildComponent 的道具被更新,从而避免不必要的重新渲染。下面是组件的最终版本:

// Example 11

import { useEffect, useState, memo, useCallback } from "react";

// this is our child component we want to optimize
const ChildComponent = memo(({ callback }) => {
console.log("Child was rendered...");
return <button onClick={callback}>Click me!</button>;
});

export const MyComponent = (props) => {
// here we have some states and variables.
const [color, setColor] = useState("#ff22ff");
const [otherState, setOtherState] = useState(false);
const otherVariables = "other variables...";

// this is our callback we want to cache.
const callbackFn = useCallback(() => {
console.log("Hello, you clicked!");
}, [props, otherState, otherVariables]); // these could be the dependencies

// this is for trigger a re-render by updating state.
useEffect(() => {
setTimeout(() => {
setColor("#00ddd2");
}, 3000);
}, []);

// this is our child component, with the callback passed as prop.
return <ChildComponent callback={callbackFn} />;
};

如果您想进一步了解 useCallback 的用法,可以继续阅读其官方文档,其中会介绍更多的使用案例。


纯组件(Pure Components)

如果一个 React 组件在相同的状态和道具下渲染相同的输出,那么它就被认为是纯组件。对于这种类型的组件,React 提供了 PureComponent 类。扩展 PureComponent 类的类组件被视为纯组件。由于 React 为纯组件实现了 shouldComponentUpdate() 方法,并对道具和状态进行了浅层比较,因此纯组件在性能和渲染方面都有一些改进和优化。

不过,如今功能组件更常用。如果您已经在使用类组件,甚至是纯类组件,您可能想了解一下如何从纯类组件迁移到功能组件。除此之外,了解纯组件的工作原理以及如何将它们用作类总是有好处的。让我们来看一些纯组件的例子。

// Example 12

import React, { Component, PureComponent, memo } from "react";

// class normal component - not optimized
class MyComponent extends Component {
render(){
return (
<div>My Component</div>
);
}
}

// class pure component - optimized - validates props and state equality
class MyComponent extends PureComponent {
render(){
return (
<div>My Component</div>
);
}
}

// functional component - not optimized
const MyComponent = (props) => <div>My Component</div>;

// functional component optimized with memo
const MyComponent = memo((props) => <div>My Component</div>);

顺便提一下,我们可以使用 shouldComponentUpdate() 方法,它是 React 调用的一个生命周期方法,用于确定组件是否应该重新渲染。默认情况下,它总是返回 true,这意味着当组件的状态或道具发生变化时,组件总是会重新渲染。

这意味着我们可以在 Component(而非 PureComponent)类中定义 shouldComponentUpdate() 方法,以优化性能。该方法接收两个参数:nextProps 和 nextState。您可以将这些值与当前的道具和状态进行比较,如果确定组件不需要重新渲染,则返回 false。

在 PureComponent 中,React 会自动为您实现 shouldComponentUpdate(),并对 props 和 state 进行浅层比较。这意味着,如果道具和状态与上次呈现时相同,组件就不会重新呈现。

在功能组件中,shouldComponentUpdate() 的等效方法是使用 React.memo 或 useMemo 钩子,通过对道具进行浅层比较并结合 useState 来处理这些组件的状态,从而避免不必要的重新渲染。


懒加载

React.lazy 是一种 React 技术,它允许我们懒散地导入组件,直到它们被首次呈现。当我们不想一次性导入整个组件包时,这就非常有用了,因为这会减慢应用程序的加载时间。React.lazy 背后的理念是通过只导入页面当时需要的组件来加快特定页面的加载速度。这对于包含许多组件的大型或复杂应用程序尤其有用。

下面我们来看看如何使用懒加载:

// Example 13

import { lazy } from 'react';

// normal import
import MyNormalComponent from './MyNormalComponent';

// lazy import
const MyLazyComponent = lazy(() => import('./MyLazyComponent'));

建议将使用 React.lazy 导入的组件封装在另一个名为 Suspense 的 React 组件中。该组件允许我们在等待懒组件加载时显示回退。在这个回退中,我们可以显示一条消息或加载动画,让用户知道有东西正在加载。下面是一个如何使用 React.Suspense 的懒惰组件的示例:

// Example 14

import { lazy, Suspense } from 'react';
import LoadingAnimation from './LoadingAnimation';

const MyLazyComponent = lazy(() => import('./MyLazyComponent'));

const MyApp = () => {
return (
<Suspense fallback={<LoadingAnimation />}>
<MyLazyComponent />
</Suspense>
);
};

需要注意的是,React.lazy 只能用于默认导出。因此,如果您的组件不是以这种方式导出的,您就必须修改组件的导出,以便 React.lazy 可以顺利地使用它。您可以在此处阅读更多相关信息。

另一个需要强调的要点是,如果您使用 create-react-app 构建了应用程序,您可以将 React.lazy 与 React Router 结合使用,后者可以通过自动生成按路由分割的代码来优化应用程序的导航。无需加载整个捆绑包,而是在您浏览应用程序时加载捆绑包。

这是因为 create-react-app 已经配置了 webpack,否则,您必须手动配置才能启用代码分割功能。下面是一个如何在 React Router 中使用懒加载的示例:

// Example 15

import { lazy, Suspense } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import LoadingAnimation from './LoadingAnimation';

// here we are importing our lazy components
const Home = lazy(() => import('./Home'));
const Login = lazy(() => import('./Login'));
const Register = lazy(() => import('./Register'));
const About = lazy(() => import('./About'));

const MyApp = () => {
return (
<Router>
<Suspense fallback={<LoadingAnimation />}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
</Router>
);
};

通过对路由使用这种技术,我们可以分离我们的捆绑包并生成称为 "块 "的更小的捆绑包,其中每个路由都包含在每个 "块 "中。因此,在加载路由时,我们不是一次性下载整个捆绑包,而是根据需要加载捆绑包。如前所述,这种技术被称为 "代码拆分",你可以在这里了解更多相关信息。最终,这将优化应用程序的加载速度,使其更加流畅,并提供更好的用户体验。


虚拟化(窗口)

React 虚拟化是一种强大的技术,用于创建只显示当前使用元素的高性能用户界面。无论是使用 React 虚拟化库还是构建自己的算法,该技术都是专为处理大型数据集和提高用户界面性能而设计的。React 中的虚拟化可以在任何给定时间内选择性地只呈现所需的元素,从而加快加载速度,带来更流畅的整体用户体验。

为了更好地理解这种技术,请参考下面的示例:


虚拟化还可应用于表格,对行和列进行虚拟化可显著提高性能。这种技术对于显示大量数据的组件(如表格)尤其有用。通过只呈现当前可见的行和列,React 中的虚拟化可以大大提高这些组件的性能。为了进一步说明这一点,让我们看看下面的示例:


如果您想实现自己的虚拟化表格或列表,我推荐您使用 react-window 软件包,它提供了虚拟化组件所需的所有工具。


错误边界(Error Boundaries)

Error Boundaries是一种 React 组件,可捕捉其子组件树中任意位置的 JavaScript 错误,记录这些错误,并显示一个后备 UI 来代替崩溃的组件树。错误边界会捕获呈现过程中的错误、生命周期方法以及其下整个组件树的构造函数。需要注意的是,错误边界不会捕获事件处理程序、异步代码或错误边界本身发生的错误。有关错误边界的更多详情,请点击此处。

下面的示例说明了如何使用 React 在组件中实现错误边界:

// Example 16

import { PureComponent } from 'react';

export class ErrorBoundaries extends PureComponent {
constructor(props) {
super(props);
this.state = { hasError: false, errorInfo: null };
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
// this is similar to => this.setState({ hasError: true })
return { hasError: true, errorInfo: error };
}

componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.log(error, errorInfo, this.state.errorInfo);
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}

// this could return the children or anything else: this.props.children;

<div>
This is the main returned component with no error yet.
</div>

}
}

使用此实现,您可以用 ErrorBoundary 组件封装任何可能会出错的组件,它将捕获并处理在它或其子组件中发生的任何错误。当发生错误时,getDerivedStateFromError 方法会更新状态以显示回退用户界面,而 componentDidCatch 方法会将错误记录到控制台或错误报告服务中。


内联函数

建议避免在 React 中使用内联函数有几个原因。以下是其中一些原因:

性能:每次在 React 中呈现组件时,都会重新创建所有内联函数。这会导致应用程序的性能降低,尤其是当您有许多使用内联函数的组件时。
维护:内联函数是在组件内定义的,不能在应用程序的其他部分重复使用。这会使代码随着应用程序的增长而更难维护。
可读性:内联函数会使代码更难阅读和理解,尤其是在代码较长或参数较多的情况下。

在下面的示例中,我们将看到每个按钮的内联函数。不过,如前所述,这可能会导致性能问题,在本例中可能并不明显,但对大型应用程序可能会产生重大影响。因此,建议在更大范围内优化这类问题。

// Example 17

import { useState } from "react";

export const InlineFunctions = () => {
const [counter, setCounter] = useState(0);

return (
<div>
<h1>{counter}</h1>
<button
onClick={() => {
setCounter((prevCount) => prevCount + 1);
}}
>
Increase Counter
</button>
<button
onClick={() => {
setCounter((prevCount) => prevCount - 1);
}}
>
Decrease Counter
</button>
</div>
);
};

在这种情况下,处理点击事件的更好方法是定义一个单独的函数来处理点击事件,然后使用该函数作为每个按钮的 onClick 事件的回调函数。这样,就不会在每次渲染组件时都重新创建函数,从而提高了性能。下面是一个使用独立函数的更新示例:

// Example 18

import { useState } from "react";

export const InlineFunctions = () => {
const [counter, setCounter] = useState(0);

const handleClick = (value) => () => {
setCounter((prevCount) => prevCount + value);
};

return (
<div>
<h1>{counter}</h1>
<button onClick={handleClick(1)}>Increase Counter</button>
<button onClick={handleClick(-1)}>Decrease Counter</button>
</div>
);
};

总之,虽然内联函数在小型组件或快速原型开发中很有用,但建议避免在大型应用程序或频繁渲染的组件中使用它们。通过将内联函数提取为可重复使用和优化的独立函数,可以提高代码的性能、维护性和可读性。在所提供的示例中,我们通过创建一个单独的函数来处理按钮点击事件,从而减少了内联函数的数量,提高了组件的整体性能,从而优化了代码。


总结

最后,我们介绍了一系列与优化 React 应用程序相关的主题。去弹、节流和 memoization 都是有助于通过减少不必要的呈现和处理来提高性能的技术。纯组件是另一项重要的优化,可确保组件仅在必要时重新呈现。

懒加载和虚拟化技术有助于改善应用程序的初始加载时间及其整体性能。懒加载允许我们只在实际需要时加载必要的组件或资源,而虚拟化(或窗口化)允许我们只渲染大型数据集的可见部分,避免对屏幕外元素进行不必要的渲染和处理。

错误边界提供了一种处理错误的方法,否则应用程序可能会崩溃。通过使用错误边界,我们可以优雅地记录和处理错误,提供一个后备用户界面,而不是应用程序完全崩溃。

最后,我们讨论了由于内联函数对性能、维护和可读性的影响,尽可能避免使用内联函数的重要性。

总之,通过在 Javascript 或 React 应用程序中实施这些技术,我们可以创建更高效、响应更快和可扩展的应用程序。

翻译来自:https://medium.com/globant/javascript-optimization-techniques-20d8d167dadd

链接: https://www.fly63.com/article/detial/12661

js中for循环优化总结_如何提高程序的执行效率

在程序开发中,经常会使用到for循环的,但是很多人写的for循环效率都是比较低的,下面就举例说明,并总结优化for循环的方法,来提高我们程序的执行效率。

网站打开速度优化_如何提高网页访问速度技巧方法总结

网站的加载速度不仅影响着用户体验,也会影响搜索引擎的排名,在百度推出“闪电算法”以来,将网站首屏打开速度被列入优化排名行列,作为前端开发的我们需要如果来优化网站的打开速度呢?下面就整理挖掘出很多细节上可以提升性能的东西分享给大家

JS性能优化之文档片段createDocumentFragment

DocumentFragments是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。因为文档片段存在于内存中,并不在DOM树中

深入浅出代码优化﹣if/else

对于代码裡面的 if else,我们可以使用逻辑判断式,或更好的三元判断式来优化代码。除了可以降低维护项目的成本之外,还可以提升代码可读性。就让我们从最简单的 if else 例子开始吧。

微信小程序性能优化入门指南

小程序从发布到现在也已经有将近两年的时间,越来越来多的公司开始重视小程序生态带来的流量,今年也由于小程序平台对外能力的越来越多的开放以及小程序平台的自身优化,越来越多的开发者也自主的投入到小程序的开发当中

网络串流播放_HTML5如何优化视频文件以便在网络上更快地串流播放

无论你正在将 GIF 动图转换为 MP4 视频,还是手头已经有一大堆 MP4 视频,你都可以优化文件结构,以使得这些视频更快地加载和播放。通过重组 atoms 将 moov 放到文件开头,浏览器可以避免发送额外的 HTTP range request 请求来搜寻和定位 moovatom

​web项目优化_Web 服务器性能与站点访问性能优化

要优化 Web 服务器的性能,我们先来看看 Web 服务器在 web 页面处理上的步骤:Web 浏览器向一个特定的服务器发出 Web 页面请求; Web 服务器接收到 web 页面请求后,寻找所请求的 web 页面,并将所请求的 Web 页面传送给 Web 浏览器; 显示出来

前端性能优化之重排和重绘

浏览器下载完页面所有的资源后,就要开始构建DOM树,于此同时还会构建渲染树(Render Tree)。(其实在构建渲染树之前,和DOM树同期会构建Style Tree。DOM树与Style Tree合并为渲染树)

微信小程序代码优化总汇

写篇文章的目的,是以开放小程序代码的层面的优化。包括:条件判断将wx:if换成了hidden 、页面跳转请销毁之前使用的资源、列表的局部更新、小程序中多张图片懒加载方案、Input状态下隐藏input,应预留出键盘收起的时间

我是如何将页面加载时间从6S降到2S的?

生活在信息爆炸的今天,我们每天不得不面对和过滤海量的信息--无疑是焦躁和浮动的,这就意味着用户对你站点投入的时间可能是及其吝啬的(当然有一些刚需站点除外)。如何给用户提供迅速的响应就显得十分重要了

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!