首页 > 其他分享 >动态加载——懒加载实现

动态加载——懒加载实现

时间:2023-11-17 17:35:50浏览次数:103  
标签:__ 实现 upload js webpack download 动态 加载

webpack 是一个现代 JavaScript 应用程序的静态模块打包器 (module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图 (dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle

前端工程化演进到今天,webpack 做了很大的贡献。项目工程化带来了很多便捷,不再需要手动处理依赖之间的关系,也可以更方便的使用更多好用的框架,可以更关注业务本身,集中精力打造产品。

在 webpack 中,使用懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。

总结

一句话就是动态 import 代码分割 + jsonp

实现背景

先假设在完成一个真实的项目,这个项目中有上传下载功能。

下载功能一般是打开一个链接,所以直接实现在主包中。而上传功能可能会使用到第三方 sdk,使用懒加载进行加载。只有在用户点击上传时,才会加载这个具备上传功能的包,来进行上传。

上传下载功能可能会使用到一些第三方 sdk,而这些第三方 sdk 的体积往往非常大,并且这个功能所以这个功能做成懒加载实现是合理的。

为了演示差别,这里将“下载”和“上传”两个功能做区分。

项目基础配置

先搭建一个基础的 webpack 配置,让其支持懒加载配置,然后直接通过打包后的代码来看看懒加载实现的效果。需要有个基础目录配置,项目 Demo 目录结构如下:

image

文件/目录 说明
src 入口文件、下载模块、上传模块
index.html html 模板文件
webpack.config.js webpack 配置文件
package.json 项目说明文件

功能代码实现

先来看看功能代码实现吧,分别是 download.jsupload.jsindex.js

// ./src/download.js
const download = () => {
  console.log("download start");

  console.log("schedule download sdk");

  console.log("download");
};

export default download;
// ./src/upload.js
const upload = () => {
  console.log("upload start");

  console.log("schedule upload sdk");

  console.log("upload");
};

export default upload;
// ./src/index.js
import download from "./download";

console.log("initial page");

async function handlerUploadClick() {
  // 动态加载 upload 模块,该模块的 default 属性就是 upload 方法
  const { default: upload } = await import("./upload");
  // 调用 upload 方法
  upload();
}

async function handlerDownloadClick() {
  download();
}

// 点击 upload 按钮时,调用上传方法
document
  .querySelector("#upload")
  .addEventListener("click", handlerUploadClick, false);

// 点击 download 按钮时,调用下载方法
document
  .querySelector("#download")
  .addEventListener("click", handlerDownloadClick, false);
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Webpack LazyLoad</title>
  </head>

  <body>
    <section>
      <h1>Home</h1>
      <button id="upload">Upload</button>
      <button id="download">Download</button>
    </section>
  </body>
</html>

在功能代码实现中,实现了一个 html 网页,其中有两个按钮,一个是上传按钮,一个是下载按钮。

配置实现

功能实现后,需要配置 webpack,然后打包生成能够直接运行的项目。

新建文件 webpack.config.js 进行配置,代码实现如下:

// webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const WebpackChain = require("webpack-chain");

// 使用 webpack chain 组装配置
const chain = new WebpackChain();

// 设置入口文件为 src/index.js
chain.entry("main").add("./src/index.js").end();

// 将构建生成的文件输出到 dist 目录
chain.output.path(path.resolve(__dirname, "./dist")).end();

// 添加 html-webpack-plugin 插件,设置 HTML 模板文件
chain.plugin("html-webpack-plugin").use(HtmlWebpackPlugin, [
  {
    template: path.resolve(__dirname, "./index.html"),
  },
]);

// 设置 source map 生成规则
chain.devtool("cheap-source-map").end();

// 将配置转成 webpack 可识别的配置对象
const config = chain.toConfig();

module.exports = config;

从代码实现中可以看出, webpack 配置只是简单配置了入口出口和 html 模板文件。

那么接下来,需要配置 package.json,在 scripts 中添加启动命令,代码实现如下:

"scripts": {
  "build": "NODE_ENV=development webpack --config webpack.config.js && cd dist && anywhere"
}

anywhere 是一个快速启动 http 服务的插件,可以使用 npm i anywhere -g 进行全局安装。

在配置完了以后,需要运行下面的命令安装一些依赖

npm i webpack webpack-cli webpack-chain html-webpack-plugin anywhere -D

安装依赖后,就可以准备启动项目!

运行项目

运行 npm build 启动项目编译,命令行输出将会是下面这样(如下图)

image

项目在被 webpack 打包后,输出到了 dist 目录,并且由 anywhere 运行了一个服务,在 8000 端口。

打开浏览器,可以看到下面这个页面。(如下图)

image

打开控制台,会看到设置的对应输出(如下图)

image

页面操作

来进行一些页面操作,先点击 Download 按钮,会发现控制台的输出变成了下面这样(如下图)

image

从上图可以看出 download 方法被调用了,此时执行了一个下载操作(mock 操作)。

那此时再点击一下 Upload 按钮,再观察控制台输出(如下图)

image

从控制台可以看到上传操作被调用了,但是似乎和下载操作没什么区别。

此时,需要切换到 network 控制面板,查看网络请求。(如下图)

image

从上图可以发现,在调用 upload 方法时,才会加载 upload 方法对应的文件,从而实现懒加载。

这样做的好处在于,可以根据需求有效减小主包的体积,加快首屏渲染速度,减少服务器带宽压力。同时也减少了 JS 解析时间,提升页面渲染速度。

懒加载的实现对前端来说,是性能优化专项必修课。可以说,项目越复杂,那么懒加载带来的好处就越大。

实现分析

下面可以来看看 webpack 编译后的代码,看看 webpack 是如何实现懒加载的。

首先,查看主包文件,也就是 dist/main.js。在这个文件里找到在 src/index.js 中实现的初始化页面操作。(如下图)

image

从上图可以看出,该操作直接被打包进了构建生成的 bundle 文件中。

Download 解析

那再来看看 src/download.js 中实现的下载方法调用(如下图)

image

从上图可以看出,handlerDownloadClick 最终调用了 _download__WEBPACK_IMPORTED_MODULE_0__.default 方法。

而这个 _download__WEBPACK_IMPORTED_MODULE_0__.default 是什么呢?

在构建后的代码中,找到了对这个对象的赋值操作(如下图)

image

__webpack_require__ 函数,其实就是加载 __webpack_modules__ 中的对应模块,这里加载的对应模块就是 "./src/download.js" 模块。

最终,在 dist/main.js 中,找到了对该模块的定义。(如下图)

image

从上图可以看出,对该模块的定义,其实就是 src/download.js 的实现,被打包进了 dist/main.js 中,成为了 __webpack_modules__ 对象的一部分。

Upload 解析

看完了 download 方法的打包实现,接下来看看懒加载的 upload 是如何实现的?

先找到 upload 对应的函数调用(如下图)

image

从上图可以看出,当点击上传按钮时,先使用 __webpack_require__.e 方法进行了一个加载操作,来看看这个方法所做的事情。

该方法先拼接了这个模块对应的绝对路径(如下图)

image

这个路径的文件其实就是打包后生成在 dist 目录的文件(如下图)

image

然后使用动态插入 script 标签的方式,将对应的脚本文件插入到文档中。(如下图)

image

upload 对应的文件被插入后,将会自动执行。src_upload_js.js 脚本文件中将会执行 webpackJsonpCallback 方法,执行后将会在 windowwebpackChunklazyload 数组插入刚才懒加载的模块。(如下图)

image

在执行该函数后,还会把 upload 模块注册在 __webpack_modules__ 中,后面的调用流程就和调用 download 一样~(如下图)

image

小结

从一个简单的案例,了解到了 webpack 的懒加载实现。

webpack 的懒加载实现在打包时会将懒加载的代码切割出去单独打包,然后在主包中进行按需加载,最后执行调用。

最后用一张图来梳理一下懒加载的加载执行过程。(如下图)

image

标签:__,实现,upload,js,webpack,download,动态,加载
From: https://www.cnblogs.com/wp-leonard/p/17839296.html

相关文章

  • 智慧工地平台,利用5G及智能终端算法,实现IOT设备数据抓取与处理
    智慧工地平台采用先进的云计算、物联网和大数据技术,可以实现智慧工地方案的落地。能够实现实时掌控工地活动及各项进度,有效预防违章施工。能够为工地提供多项服务,如安全预警、机械智能监控、作业指导、绿色施工、劳务管理、工程进度监控、施工质量检查等。可实时收录及通知施工进度......
  • MATLAB/Simulink中调用C语言实现的传递函数
    1.引言在变流器控制中,通常采用C语言实现传递函数,且通常写成独立的C文件,本文简要介绍如何在MATLAB/Simulink中调用这些C文件。在本文中,采用C语言实现了一阶低通滤波器、二阶低通滤波器、滑动平均滤波器,具体代码见附录。同时需要安装C编译工具链,参考《UsingGCCwithMinGW》。2......
  • 纯CSS3实现圆圈动态发光特效动画
    参考文档:https://www.cnblogs.com/cyfeng/p/12625606.htmlhtml文件: <div class="item"></div>css文件:     <!DOCTYPEHTML><html><head><title>纯CSS3实现圆圈动态发光特效动画</title><style>bo......
  • 前端页面的懒加载和预加载
    前言懒加载也就是延迟加载。当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,从而减轻服务器压力,避免用户等待时间过长(一般在网站图片很多......
  • Vue 该如何实现组件缓存?
    在面向组件化开发中,我们会把整个项目拆分为很多业务组件,然后按照合理的方式组织起来,那么自然会存在组件之前切换的问题,vue中有个动态组件的概念,它能够帮助开发者更好的实现组件之间的切换。但是在面对需求频繁的变化,切换组件时,动态组件在切换的过程中,组件的实例都是重新创建的,而......
  • Vue3 模板引用 ref 的实现原理
    什么是模板引用ref?有时候可以使用 ref attribute为子组件或HTML元素指定引用ID。<template><inputref="input"/></template><script>import{defineComponent,ref}from"vue";exportdefaultdefineComponent({setup(){......
  • Vue3 的 effect、 watch、watchEffect 的实现原理
    所谓watch,就是观测一个响应式数据或者监测一个副作用函数里面的响应式数据,当数据发生变化的时候通知并执行相应的回调函数。Vue3最新的watch实现是通过最底层的响应式类ReactiveEffect的实例化一个reactiveeffect对象来实现的。它的创建过程跟effectAPI的实现类似,所......
  • Vue插槽(Slot)的实现原理
    实现原理(简单文字)slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot又分三类,默认插槽,具名插槽和作用域插槽实现原理:当子组件vm......
  • 实现无感刷新token
    目录需求实现问题解决注意事项:需求当token过期的时候,刷新token,前端需要做到无感刷新token,即刷token时要做到用户无感知,避免频繁登录。实现思路方法一后端返回过期时间,前端判断token过期时间,去调用刷新token接口缺点:需要后端额外提供一个token过期时间的字段;使......
  • 实现多个大文件拖拽上传+大文件分片上传+断点续传+文件预览
    技术关键词前端:@vue/cli-service+element-ui+axios后端:node.js+koa思路分析拖拽上传拖拽上传是利用HTML5新特性实现拖拽上传,详细用法可阅读MDN-drag利用dragover事件(当某物被拖动的对象在另一对象容器范围内拖动时触发此事件)和drop事件(在一个拖动过程中,释放鼠标键时......