by José M. Pérez

由JoséM.Pérez

通过延迟加载和代码拆分提高网站性能 (Improve the Performance of your Site with Lazy-Loading and Code-Splitting)

在需要时如何使用高阶组件加载所需的内容。 (How to use a High-Order Component to load what is needed, when needed.)

Componentization has marked a before and after in web development. The main advantages that are usually mentioned are reusability and modularization. Components are well defined pieces that we can use to build our sites, like bricks of Legos. It turns out this component structure provides a great foundation to improve the performance of our sites.

组件化标志着Web开发的前后。 通常提到的主要优点是可重用性和模块化。 组件是定义明确的片段,可用于构建站点,例如,乐高积木。 事实证明,此组件结构为改善我们的网站的性能提供了良好的基础。

We are explicit about our dependencies, so we know what code we need to run a specific component. Lazy-loading and bundle splitting can have a huge impact on page performance: less code requested, parsed, and executed. And this not only applies to JavaScript, but every type of asset.

我们对依赖项很明确,因此我们知道运行特定组件需要什么代码。 延迟加载和包拆分可能会对页面性能产生巨大影响:更少的请求,解析和执行代码。 这不仅适用于JavaScript,而且适用于每种资产。

I see many sites that could take advantage of this. I wanted to show some basic techniques to load content as needed.

我看到许多网站都可以利用这一优势。 我想展示一些基本技术来根据需要加载内容。

The article will be using Preact/React, yet the ideas can be applied to any other component library.

本文将使用Preact / React,但是这些思想可以应用于任何其他组件库。

We are going to cover several topics.

我们将讨论几个主题。

Let’s start!

开始吧!

组成模式 (Compositional Patterns)

In a component, world components aren’t only used for rendering actual pixels on the screen. They can also wrap functionality that is passed to children components.

在组件中,世界组件不仅用于在屏幕上渲染实际像素。 他们还可以包装传递给子组件的功能。

This is usually achieved using High Order Components (HOC). These components receive another component and add some functionality, like a behavior.

这通常是使用高阶组件(HOC)实现的 。 这些组件接收另一个组件并添加一些功能,例如行为。

If you have used redux, the connect function is a HOC that receives your not-connected component. You can find more examples in “React Higher Order Components in depth“ by Fran Guijarro.

如果您使用过redux,则connect函数是一个HOC,用于接收未连接的组件。 您可以在 Fran Guijarro的“ 深度React高阶组件 ”中找到更多示例。

const MyComponent = props => (  <div>    {props.id} - {props.name}  </div>);
// ...
const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)( MyComponent );

Function as Child Component (also known as “Render Callback“) is another pattern used in similar scenarios. It is getting quite popular these days. You might have come across them in react-media or unstated.

用作子组件(也称为“ 渲染回调 ”)是在类似情况下使用的另一种模式。 这些天它变得非常流行。 你可能会遇到他们的React介质或不成文的 。

Look at this example taken from react-media:

看下面这个来自react-media的例子:

const MyComponent = () => (  <Media query="(max-width: 599px)">    {matches =>      matches ? (        <p>The document is less than 600px wide.</p>      ) : ( <p>The document is at least 600px wide.&lt;/p>      )    }  </Media>);

The Media component calls its children passing a matches argument. This way, the children components don’t need to know about the media query. Componentizing generally makes testing and maintenance easier.

Media组件通过一个matches参数调用其子级。 这样,子组件不需要了解媒体查询。 组件化通常使测试和维护更加容易。

通过仅加载所需内容来提高我们网站的性能 (Improving performance of our sites by loading only what is needed)

Imagine a typical web page. You can check Website Sameness or Web Design Trends: Why Do All Websites Look The Same? for some inspiration :) . The example page we are going to use contains several sections or blocks:

想象一个典型的网页。 您可以检查网站相同性或Web设计趋势:为什么所有网站看起来都一样? 一些灵感:)。 我们将使用的示例页面包含几个部分或块:

  • a header (these days, a large hero image taking the whole above-the-fold area)标头(这些天,大英雄图像占据了整个首屏区域)
  • a section with a few images带有一些图像的部分
  • another section with a heavy component like a map另一个部分,例如地图
  • a footer页脚

This, mapped into React components, would be something like this:

映射到React组件中的代码将是这样的:

const Page = () => {  <div>    <Header />    <Gallery />    <Map />    <Footer />  </div>};

When the user visits the page, it is highly likely that they will see the header on screen. After all, it’s the top most component. It is less likely that they see the gallery, map, and footer unless they scroll.

当用户访问页面时,很有可能会在屏幕上看到标题。 毕竟,它是最重要的组件。 除非滚动,否则他们不太可能看到画廊,地图和页脚。

Most times you would include all the scripts and CSS needed to render all sections as soon as the user visits the page. Until recently it was difficult to define a module’s dependencies, and load what was needed.

大多数情况下,您会在用户访问页面时包括呈现所有部分所需的所有脚本和CSS。 直到最近,很难定义模块的依赖关系并加载所需的内容。

Years ago, pre-ES6, large companies came up with their own solutions to define dependencies and load them as needed. Yahoo built YUI Loader and Facebook wrote Haste, Bootloader and Primer.

多年以前,在ES6之前,大公司想出了自己的解决方案来定义依赖项并根据需要加载它们。 雅虎建立了YUI Loader ,Facebook编写了Haste,Bootloader和Primer 。

When you send the user code that is not needed, you waste resources on your end, and from the user’s end. More bandwidth to transfer the data, more CPU to parse and execute them, and more memory to keep around. And those assets will steal the limited resources from other critical assets that need it more urgently.

当发送不需要的用户代码时,浪费了资源,浪费了用户端的资源。 更多的带宽来传输数据,更多的CPU来解析和执行它们,以及更多的内存来保留。 这些资产将从其他迫切需要的关键资产中窃取有限的资源。

What’s the point in requesting resources that the user will not need, like images that the user won’t reach? Or loading a 3rd party component like a Google Map, with all its additional assets needed to render the thing?

请求用户不需要的资源(例如用户无法访问的图像)有什么意义? 还是要加载第3方组件(例如Google Map),以及渲染事物所需的所有其他资产?

A code coverage report, like the one Google Chrome provides won’t help us much. The JS code will be executed and the CSS applied to elements that aren’t visible.

像Google Chrome浏览器所提供的那样,一份代码覆盖率报告对 我们没有多大帮助 。 将执行JS代码,并将CSS应用于不可见的元素。

As with everything else, there are trade-offs with lazy-loading. We don’t want to apply lazy-loading to everything. Here are some points to take into account.

与其他所有内容一样, 在延迟加载中需要权衡取舍 。 我们不想将延迟加载应用于所有内容。 这里有几点要考虑。

  • Don’t lazy load above the fold. In most cases we want the above-the-fold content to be rendered as soon as possible. Every lazy-loading technique will introduce a delay. The browser has to run the JS that injects the HTML into the document, parse it and start requesting the referenced assets.

    不要懒洋洋地在褶皱上方装载 。 在大多数情况下,我们希望尽快显示首屏内容。 每种延迟加载技术都会带来延迟。 浏览器必须运行JS,该JS将HTML注入文档中,进行解析,然后开始请求引用的资产。

Where to set the fold? This is tricky, and it will depend on the user’s device, which varies greatly, and your layout.

在哪里设置折页? 这很棘手,这将取决于用户的设备(布局差异很大),而用户的设备差异很大。

  • Lazy load a bit earlier than when it’s needed. You want to avoid showing void areas to the user. For this, you can load an asset that is needed when it’s close enough to the visible area. For instance, a user scrolls down and if the image to load is, let’s say, 100px below the bottom of the viewport, start requesting it.

    延迟加载要比需要时提前加载 。 您要避免向用户显示空白区域。 为此,您可以加载足够接近可见区域的资产。 例如,用户向下滚动,如果要加载的图像位于视口底部下方100px,则开始请求它。

  • Invisible content in some scenarios. You need to take into account that lazy-loaded content won’t be shown in some situations:

    在某些情况下不可见的内容 。 您需要考虑到在某些情况下不会显示延迟加载的内容:

1) If the lazy-loaded content hasn’t been loaded it won’t show up when printing the page.

1)如果尚未加载延迟加载的内容,则在打印页面时将不会显示。

2) The same can happen when the page is shown in RSS readers that might not execute the Javascript needed to load the content.

2)当页面显示在RSS阅读器中时,可能无法执行加载内容所需的Javascript,同样可能发生。

3) When it comes to SEO, you might have issues indexing lazy-loaded content on Google. At the time of writing this article, Googlebot supports IntersectionObserver. It invokes its callback with changes in the viewport above the fold. However, it won’t trigger the callback for content below the fold. Thus, that content won’t be seen nor indexed by Google. If your content is important you can, for instance, render the text and lazy-load components like images and other widgets (eg maps).

3)关于SEO,您可能在索引Google上的延迟加载内容时遇到问题。 在撰写本文时,Googlebot支持IntersectionObserver。 它使用折叠上方视口中的更改来调用其回调。 但是, 它不会触发fold以下内容的回调 。 因此, 该内容不会被Google查看或索引 。 如果您的内容很重要,则可以渲染文本和惰性加载组件,例如图像和其他小部件(例如地图)。

Here I’m rendering a test page (you can see the source here) using Google Webmaster Tools’ “Fetch as Google”. Googlebot renders the content in the box shown within the viewport, but not the content below it.

在这里,我使用Google网站站长工具的“以Google身份提取”来呈现测试页 (您可以在此处查看源代码)。 Googlebot会在视口内的框中显示内容,但不显示其下方的内容。

检测区域何时可见的小组件 (A small component to detect when an area is visible)

I have talked in the past about lazy-loading images. This is just a type of asset that we can lazy-load, but we can apply the technique to other elements.

我过去谈论过延迟加载图像 。 这只是我们可以延迟加载的一种资产,但是我们可以将该技术应用于其他元素。

Let’s build a simple component that will detect when the section is visible in the viewport. For brevity, I will use the Intersection Observer API, an experimental technology with quite good support.

让我们构建一个简单的组件,该组件将检测该部分何时在视口中可见。 为简便起见,我将使用Intersection Observer API ,这是一种具有很好支持的实验技术。

class Observer extends Component {  constructor() {    super();    this.state = { isVisible: false };    this.io = null;    this.container = null;  }  componentDidMount() {    this.io = new IntersectionObserver([entry] => {      this.setState({ isVisible: entry.isIntersecting });    }, {});    this.io.observe(this.container);  }  componentWillUnmount() {    if (this.io) {      this.io.disconnect();    }  }  render() {    return (      // we create a div to get a reference.      // It's possible to use findDOMNode() to avoid      // creating extra elements, but findDOMNode is discouraged      <div        ref={div => {          this.container = div;        }}      >        {Array.isArray(this.props.children)          ? this.props.children.map(child => child(this.state.isVisible))          : this.props.children(this.state.isVisible)}      </div>    );  }}

The component uses IntersectionObserver to detect that the container intersects with the viewport (meaning it’s visible). We take advantage of React’s lifecycle methods to clean up the IntersectionObserver, disconnecting it when unmounting.

该组件使用IntersectionObserver来检测容器与视口相交(意味着它是可见的)。 我们利用React的生命周期方法来清理IntersectionObserver, 并在卸载时断开它的连接 。

This basic component could be extended with extra properties passed as options to IntersectionObserver, like margins or thresholds. This allows us to detect elements close to but not intersecting with the viewport. The options are set in the constructor, and they are read-only. Thus, adding support for options means that we would need to reinstantiate the IntersectionObserver with new options when they change, adding some extra logic in componentWillReceiveProps that we are not going to cover here.

可以通过将其他属性作为选项传递给IntersectionObserver来扩展此基本组件,例如边距或阈值。 这使我们能够检测接近但不与视口相交的元素。 这些选项在构造函数中设置,并且是只读的。 因此,添加对选项的支持意味着我们需要在更改新选项时重新实例化IntersectionObserver,并在componentWillReceiveProps中添加一些额外的逻辑,我们将在此处不介绍。

Now, we can use this component to lazy load two of our components, Gallery and Map:

现在,我们可以使用此组件来延迟加载我们的两个组件GalleryMap

const Page = () => {    <div>        <Header />        <Observer>          {isVisible => <Gallery isVisible />}        </Observer>        <Observer>          {isVisible => <Map isVisible />}        </Observer>        <Footer />    </div>}

In the code above I’m just passing the isVisible property to the Gallery and Map components so they handle it. Alternatively we could return the component if visible, or an empty element otherwise.

在上面的代码中,我只是将isVisible属性传递给GalleryMap组件,以便它们进行处理。 或者,我们可以返回该组件(如果可见),否则返回一个空元素。

In any case, make sure that you reserve the area for the lazy-loaded component. You don’t want content to jump around, so if you know that your Map is 400px height, render a 400px height empty container before the map is rendered.

无论如何,请确保为延迟加载的组件保留该区域 。 您不希望内容跳来跳去,因此,如果您知道Map的高度为400px,请在呈现地图之前渲染一个400px高度的空容器。

How do the Map and Gallery components use the isVisible property? Let’s take a look at the Map:

MapGallery组件如何使用isVisible属性? 让我们看一下Map

class Map extends Component {  constructor() {    super();    this.state = { initialized: false };    this.map = null;  }
initializeMap() {    this.setState({ initialized: true });    // loadScript loads an external script, its definition is not included here.    loadScript("https://maps.google.com/maps/api/js?key=<your_key>", () => {      const latlng = new google.maps.LatLng(38.34, -0.48);      const myOptions = { zoom: 15, center: latlng };      const map = new google.maps.Map(this.map, myOptions);    });  }
componentDidMount() {    if (this.props.isVisible) {      this.initializeMap();    }  }
componentWillReceiveProps(nextProps) {    if (!this.state.initialized && nextProps.isVisible) {      this.initializeMap();    }  }
render() {    return (      <div        ref={div => {          this.map = div;        }}      />    );  }}

When the container is displayed in the viewport we make a request to inject Google Map’s script. Once loaded, we create the map. This is a good example of lazy-loading JavaScript that is not needed from the beginning, and the rest of resources needed to display the map.

当容器显示在视口中时,我们将请求注入Google Map的脚本。 加载后,我们将创建地图。 这是一个很好的例子,它从一开始就不需要延迟加载JavaScript,而其余资源则需要显示地图。

The component has a state to avoid reinjecting the Google Map’s script.

该组件具有避免重新注入Google Map脚本的状态。

Let’s have a look at the Gallery component:

让我们看一下Gallery组件:

class Gallery extends Component {  constructor() {    super();    this.state = { hasBeenVisible: false };  }  componentDidMount() {    if (this.props.isVisible) {      this.setState({ hasBeenVisible: true });    }  }  componentWillReceiveProps(nextProps) {    if (!this.state.hasBeenVisible && nextProps.isVisible) {      this.setState({ hasBeenVisible: true });    }  }  render() {    return (      <div>        <h1>Some pictures</h1>        Picture 1        {this.state.hasBeenVisible ? (          <img src="http://example.com/image01.jpg" width="300" height="300" />        ) : (          <div className="placeholder" />        )}        Picture 2        {this.state.hasBeenVisible ? (          <img src="http://example.com/image02.jpg" width="300" height="300" />        ) : (          <div className="placeholder" />        )}      </div>    );  }}

The above example defines another stateful component. In fact, we are storing in the state the same information as we did with the Map.

上面的示例定义了另一个有状态组件。 实际上,我们在状态中存储的信息与Map

If the Gallery is shown within the viewport and afterward it is outside the viewport, the images will remain in the DOM. In most cases, this is what we want when working with images.

如果“图库”显示在视口内,之后又显示在视口外,则图像将保留在DOM中。 在大多数情况下,这就是我们处理图像时想要的。

无状态子组件 (Stateless Child Components)

A stateless component could also be interesting. It would allow us to unload images that are not visible anymore, showing back the placeholders:

无状态组件也可能很有趣。 这将使我们能够卸载不再可见的图像,并显示占位符:

const Gallery = ({ isVisible }) => (  <div>    <h1>Some pictures</h1>;    Picture 1    {isVisible ? (      <img src="http://example.com/image01.jpg" width="300" height="300" />    ) : (      <div className="placeholder" />    )}    Picture 2    {isVisible ? (      <img src="http://example.com/image02.jpg" width="300" height="300" />    ) : (      <div className="placeholder" />    )}  </div>);

If you do this, make sure that the images have the right cache response headers. This is so subsequent requests from the browser hit the cache and it doesn’t download the images again.

如果这样做,请确保图像具有正确的缓存响应标头。 这样一来,来自浏览器的后续请求就会进入缓存,并且不会再次下载图像。

If you find yourself making your lazy-loaded components stateful only to track that they have been visible at least once, you can add this logic to the Observer component. After all, Observer is already stateful and it can easily call its children with an additional hasBeenVisible argument.

如果您发现使延迟加载的组件处于有状态仅是为了跟踪它们至少可见一次,则可以将此逻辑添加到Observer组件。 毕竟, Observer已经是有状态的,并且可以使用附加的hasBeenVisible参数轻松地调用其子hasBeenVisible

const Page = () => {  ...  <Observer>    {(isVisible, hasBeenVisible) =>      <Gallery hasBeenVisible /> // Gallery can be now stateless    }  &lt;/Observer>  ...}

Another option is to have a variant of the Observer component that only passes a prop like hasBeenVisible. This has the advantage that we can disconnect the IntersectionObserver as soon as the element is in view since we are not going to change its value. We will call this component ObserverOnce:

另一个选择是让Observer组件的变体仅传递hasBeenVisible类的hasBeenVisible 。 这样做的好处是,一旦元素出现,我们就可以断开IntersectionObserver的连接,因为我们不会更改其值。 我们将这个组件称为ObserverOnce

class ObserverOnce extends Component {  constructor() {    super();    this.state = { hasBeenVisible: false };    this.io = null;    this.container = null;  }  componentDidMount() {    this.io = new IntersectionObserver(entries => {      entries.forEach(entry => {        if (entry.isIntersecting) {          this.setState({ hasBeenVisible: true });          this.io.disconnect();        }      });    }, {});    this.io.observe(this.container);  }  componentWillUnmount() {    if (this.io) {      this.io.disconnect();    }  }  render() {    return (      <div        ref={div => {          this.container = div;        }}      >        {Array.isArray(this.props.children)          ? this.props.children.map(child => child(this.state.hasBeenVisible))          : this.props.children(this.state.hasBeenVisible)}      &lt;/div>    );  }}

更多用例 (More use cases)

We have used the Observer component to load resources on-demand. We can also use it to start animating a component as soon as a user sees it.

我们已经使用Observer组件按需加载资源。 一旦用户看到它,我们也可以使用它来开始对组件进行动画处理。

Here is an example taken from the React Alicante website. It animates some conference numbers as soon as the user scrolls to that section.

这是取自React Alicante网站的示例。 用户滚动到该部分时,它将为一些会议编号设置动画。

We could recreate it like this (see example on Codepen):

我们可以像这样重新创建它(请参阅Codepen上的示例 ):

class ConferenceData extends Component {  constructor() {    super();    this.state = { progress: 0 };    this.interval = null;    this.animationDuration = 2000;    this.startAnimation = null;  }  componentWillReceiveProps(nextProps) {    if (      !this.props.isVisible &&      nextProps.isVisible &&      this.state.progress !== 1    ) {      this.startAnimation = Date.now();      const tick = () => {        const progress = Math.min(          1,          (Date.now() - this.startAnimation) / this.animationDuration        );        this.setState({ progress: progress });        if (progress < 1) {          requestAnimationFrame(tick);        }      };      tick();    }  }  render() {    return (      <div>        {Math.floor(this.state.progress * 3)} days ·        {Math.floor(this.state.progress * 21)} talks ·        {Math.floor(this.state.progress * 4)} workshops ·        {Math.floor(this.state.progress * 350)} attendees      </div>    );  }}

Then, we would use it exactly as the rest of components. This shows the power of abstracting the visibility detection logic outside the components that need them.

然后,我们将它与其余组件完全一样使用。 这显示了将可见性检测逻辑抽象到需要它们的组件之外的力量。

Polyfilling IntersectionObserver按需 (Polyfilling IntersectionObserver on-demand)

So far we have been using IntersectionObserver to detect when an element becomes visible. At the time of this writing some browsers (e.g. Safari) don’t have support for it, so the instantiation of IntersectionObserver will fail.

到目前为止,我们一直在使用IntersectionObserver来检测元素何时可见。 在撰写本文时,某些浏览器(例如Safari)不支持它,因此IntersectionObserver的实例化将失败。

An option would be to set isVisible to true when IntersectionObserver is not available. This, in practice, would disable lazy-loading. In a way we would consider lazy-loading as a progressive enhancement:

当IntersectionObserver不可用时,可以选择将isVisible设置为true 。 实际上,这将禁用延迟加载。 在某种程度上,我们将延迟加载视为渐进式增强:

class Observer extends Component {  constructor() {    super();    // isVisible is initialized to true if the browser    // does not support IntersectionObserver API    this.state = { isVisible: !(window.IntersectionObserver) };    this.io = null;    this.container = null;  }  componentDidMount() {    // only initialize the IntersectionObserver if supported    if (window.IntersectionObserver) {      this.io = new IntersectionObserver(entries => {        ...      }    }  }}

Another option, which I prefer, is to include a polyfill like w3c’s IntersectionObserver polyfill. This way IntersectionObserver will work in all browsers.

我更喜欢的另一种选择是包括一个类似w3c的IntersectionObserver polyfill的polyfill 。 这样,IntersectionObserver将在所有浏览器中运行。

Following with the topic of loading resources on demand, and to lead by example, we will take advantage of code-splitting to only request the polyfill if needed. That way browsers supporting the API don’t need to fetch the polyfill:

以按需加载资源为主题,并以示例为先,我们将利用代码拆分的优势,仅在需要时请求polyfill。 这样,支持API的浏览器就不需要获取polyfill了:

class Observer extends Component {  ...  componentDidMount() {    (window.IntersectionObserver      ? Promise.resolve()      : import('intersection-observer')    ).then(() => {      this.io = new window.IntersectionObserver(entries => {        entries.forEach(entry => {          this.setState({ isVisible: entry.isIntersecting });        });      }, {});      this.io.observe(this.container);    });  }  ...}

You can see a demo here (check the code source). Safari will make an extra request to load the intersection-observer npm package, since it doesn’t support IntersectionObserver.

您可以在此处查看演示 (检查代码源 )。 Safari会额外请求加载“ intersection-observer npm包,因为它不支持IntersectionObserver。

This is achieved thanks to code splitting. There are tools like Parcel or Webpack that will create a bundle for that imported package, and the logic needed to request the file.

这要归功于代码拆分。 有诸如Parcel或Webpack之类的工具可以为该导入的软件包创建捆绑,以及请求文件所需的逻辑。

代码拆分和CSS-in-JS (Code Splitting and CSS-in-JS)

So far we have seen how to use a HOC to detect that an element is within the viewport. We have also seen how to load extra JavaScript when needed.

到目前为止,我们已经看到了如何使用HOC来检测元素在视口中。 我们还看到了如何在需要时加载额外JavaScript。

Code-splitting is quite common and straightforward to implement at route level. The browser loads additional bundles as the user navigates across different URLs on the site. Tools like react-router and Next.js have made this straightforward to implement.

代码拆分在路由级别非常普遍且易于实现。 当用户浏览站点上的不同URL时,浏览器将加载其他捆绑软件。 诸如react-router和Next.js之类的工具使这一点易于实现。

Through the examples on this post, we have seen that the same can be achieved within the same route, loading the code for components on-demand. This is very useful if we have components that need a lot of specific code, not only JavaScript.

通过这篇文章中的示例,我们已经看到可以在同一条路线上实现相同的目标,并按需加载组件的代码。 如果我们的组件需要大量特定的代码,而不仅仅是JavaScript,这将非常有用。

A component could link to other resources or even inline them. Think of SVGs or CSS styles.

组件可以链接到其他资源,甚至可以内联它们。 考虑一下SVG或CSS样式。

There is no point in requesting styles that aren’t going to be applied to any element. Dynamically requesting and injecting CSS causes a FOUC (Flash of Unstyled Content). The browser shows the HTML elements with the existing style. Once the additional styles are injected it re-styles the content. With the advent of CSS-in-JS (or JSS) solutions, this is no longer a problem. CSS is inlined within the component, and we get true code splitting for our components. With CSS-in-JS we take code splitting further, loading CSS on demand.

请求样式将不会应用于任何元素是没有意义的。 动态请求和注入CSS会导致FOUC(未样式化内容的闪烁)。 浏览器显示具有现有样式HTML元素。 一旦注入了其他样式,它将对内容进行重新样式设置。 随着CSS-in-JS(或JSS)解决方案的出现,这不再是问题。 CSS内联在组件内,我们可以为组件获得真正的代码拆分。 使用CSS-in-JS,我们可以进一步拆分代码,按需加载CSS。

有用的实现 (Useful implementations)

In this post, I have explained how to implement a basic Observer component. There are existing implementations of similar components that have been more battle-tested, support more options and provide extra ways to integrate in your project.

在这篇文章中,我已经解释了如何实现基本的Observer组件。 现有类似组件的实现经过了更多的实战测试,支持更多的选项,并提供了集成到项目中的其他方式。

I definitely recommend you to check out these 2 libraries:

我绝对建议您检查以下两个库:

结论 (Conclusion)

Hopefully, I have shown how componentization can make code-splitting and loading resources on demand easier than ever. Define what your code depends on and leverage bundlers and modern tools to request the dependencies as needed when the user navigates to new paths or new components are shown on the page.

希望我已经展示了组件化如何使代码拆分和按需加载资源比以往更加容易。 定义代码所依赖的内容,并在用户导航到页面上显示的新路径或新组件时,根据需要使用捆绑器和现代工具来请求依赖项。

I would like to thank @alexjoverm, @aarongarciah and @FlavioCorpa for reviewing the post, researching similar topics and recommending tools to provide the examples on the page.

我要感谢@alexjoverm , @aarongarciah和@FlavioCorpa审查了这篇文章,研究了类似的主题并推荐了在页面上提供示例的工具。

Did you see any typo or wrong information? In that case, drop me a line.

您看到任何错字或错误信息吗? 在这种情况下,请给我留言 。

Read more from me on my website.

从我的网站上了解更多信息 。

翻译自: https://www.freecodecamp.org/news/increase-the-performance-of-your-site-with-lazy-loading-and-code-splitting-87258bbfc89b/

通过延迟加载和代码拆分提高网站性能相关推荐

  1. Vue性能优化:如何实现延迟加载和代码拆分?

    移动优先方法已经成为一种标准,但不确定的网络条件导致应用程序快速加载变得越来越困难.在本系列文章中,我将深入探讨我们在Storefront应用程序中所使用的Vue性能优化技术,你们也可以在自己的Vue ...

  2. ideal如何快速导入import_Vue性能优化:如何实现延迟加载和代码拆分?

    作者|Filip Rakowski 译者|薛命灯 移动优先方法已经成为一种标准,但不确定的网络条件导致应用程序快速加载变得越来越困难.在本系列文章中,我将深入探讨我们在 Storefront 应用程序 ...

  3. 如何加速 Web 应用程序并提高网站性能

    我们不需要提醒你快速网站加载的重要性.要么是 3 秒,要么是用户离开,因此你必须优化网站性能以符合用户的期望. 网站性能的优化是一件大事.它涉及多个方面需要照顾,其中许多取决于网站本身.其复杂性和元素 ...

  4. 分享Web应用运行的细节问题:预编译提高网站性能、跟踪用户习惯和解决线程同步...

    在这个文章里,我将分享一下在iOpenWorks.com这个网站试运行中碰到的若干问题和解决方案,这些问题包含了:(1)如何通过ASP.NET MVC预编译提高性能:(2)如何知道网站在运行中,用户响 ...

  5. 关于提高网站性能的几点建议(二)

    在 上一篇 中,从HTTP请求到页面渲染几个方面对提高网站性能提出了几点建议,本文是学习Steve Sounders的另外一本书<高性能网站建设进阶指南>之后,从JavaScript性能的 ...

  6. 提高网站性能的方法(学习笔记)

    1.缓存 对那些经常使用的数据和需要大量的时间来创建的数据可以存储在内存中,后来的请求直接使用,不需要在从新生成, 使用方法很简单: <%@OutputCache VaryByParams=&q ...

  7. html5不支持硬件加速,CSS开启硬件加速来提高网站性能-HTML5综合

    CSS开启硬件加速来提高网站性能-HTML5综合 本文由 文梅画史 于 2016-1-28 5:09 发布在 HTML5综合 在桌面端和移动端用CSS开启硬件加速 CSS animations, tr ...

  8. 海外租用主机如何提高网站性能和用户体验

    海外租用主机如何提高网站性能和用户体验 在全球化的今天,海外租用主机成为了许多企业和网站主人的选择,以便于提高网站性能和用户体验.租用海外主机的好处是可以让网站在国内外都有良好的访问速度和稳定性,还可 ...

  9. 利用 squid 反向代理提高网站性能

    本文在介绍 squid 反向代理的工作原理的基础上,指出反向代理技术在提高网站访问速度,增强网站可用性.安全性方面有很好的用途.作者在具体的实验环境下,利用 DNS 轮询和 Squid 反向代理技术, ...

最新文章

  1. 智慧健康,协同发展:清华大学携手天津市共同探索健康医疗大数据
  2. 【国内首家】第一个基于语音生成实时知识图谱的系统来啦!!!
  3. 开源桌面系统及设计图、下载地址
  4. alpha事后诸葛亮
  5. android androidx版本,Android AndroidX 简介与迁移
  6. Android布局大全
  7. 【Python可视化】Windows 10系统上Pyecharts安装教程
  8. 平衡二叉树AVL详解
  9. WildFly 8.2.0.Final版本–更改的快速概述
  10. PyTorch 学习笔记(三):transforms的二十二个方法
  11. 查看aix下安装并升级的C/C++ compiler 的版本
  12. linux 两个mysql_Linux 安装两个MySQL
  13. CSDN如何获取下载分以及进入下载频道必须知道的规则
  14. android json解析歌词,网易云歌词获取
  15. 【CSS】设置 border 长度
  16. mysql spatial索引_空间索引Spatial Indexing
  17. CocoStudio图片资源加密
  18. 八、基于FPGA的以太网协议介绍(二)
  19. Springboot:商品库存并发更新,乐观锁失败重试机制
  20. 分布式系统中间件整理

热门文章

  1. 数组的升序 java
  2. centos-安装ifconfig
  3. 索引导航-第三版-pyhui
  4. linux-vim编辑器简览
  5. temp191706考核点一,小结
  6. Confluence 6 匿名用户
  7. WPF MVVC 基础 - 父子窗体
  8. 网络电话全民亲情祝福 中秋团圆新方式
  9. 用最科学的方法展示最形象的图表——前段数据可视化选型实践
  10. 我的架构设计~用层关系图说说mvc,mvvm,soa,ddd - 张占岭 - 博客园