当前位置: 首页 > news >正文

js加载和长任务

js加载和长任务

本文将讲解以下浏览器如何加载js,并介绍一些可以提高网页加载速度的方法。

Evaluate Script

如果我们在devtoolsperformance中分析过网站的加载性能,可能会看到一个很长的任务,叫做Evaluate Script.

在这里插入图片描述

在这种情况下,该工作足以导致长时间任务,从而阻止主线程承担其他工作(包括驱动用户交互的任务).

Evaluate Script是在浏览器中执行 JavaScript 的必要部分,因为 JavaScript在执行前即时编译。当评估脚本时,首先会分析它是否有错误。如果解析器没有发现错误,则脚本将被编译为字节码,然后可以继续执行。

因为用户可能会在页面最初显示后不久就尝试与页面进行交互=,这样就会导致Evaluate Script出现问题(页面已呈现并不意味着页面已完成加载。由于页面正忙于评估脚本,因此加载期间发生的交互可能会延迟)。

总阻塞时间 (TBT)是一个可以让我们深入了解页面加载期间是否发生过多脚本评估的指标,因为它是一种负载响应指标。

script和评估它们的任务之间的关系

负责脚本评估的任务如何启动取决于网站正在加载的脚本是否是通过常规<script>元素加载的,或者脚本是否是使用type=module. 由于浏览器倾向于以不同的方式处理事物,因此主要浏览器引擎如何处理脚本评估将涉及它们之间的脚本评估行为的不同之处。

使用script元素

分派评估脚本的任务数量通常与页面上的<script>元素数量有直接关系。每个<script>元素都会启动一个任务来评估所请求的脚本,以便可以对其进行解析、编译和执行。

我们可以通过避免加载大块 JavaScript 来分解脚本评估工作,并使用其他<script>元素加载更多单独的、更小的脚本。

由于设备的功能各不相同,因此很难为单个脚本的大小定义一个设定的限制。为了在压缩效率、下载时间和脚本评估时间之间取得良好的平衡,每个脚本的大小限制为 100 KB 是一个不错的指标。

因此我们在页面加载期间应该加载尽可能少的 JavaScript,通过拆分脚本可确保我们拥有大量不会阻塞主线程的较小任务,而不是一个可能阻塞主线程的大型任务。

在这里插入图片描述

由于页面 HTML 中存在多个<script>元素,因此产生了多个任务来评估脚本。这比向用户单独发送一个体积非常大的js包更好,因为这样更有可能阻塞主线程。

在script元素添加type=module属性

通过在script元素上添加type=module属性可以在浏览器中本地加载 ES 模块。这种脚本加载方法具有一些开发人员体验优势,例如在生产环境中不需要转换代码就可以使用。但是,以这种方式加载脚本会根据浏览器的不同而具有不同的任务。

基于 Chromium 的浏览器

Chrome 等浏览器(或衍生自 Chrome 的浏览器)中,使用type=module属性加载 ES 模块会产生与不使用时看到不同类型的任务。例如,每个将执行的模块脚本(携带type=module)的任务,都呗标记为Compile module tasks

在这里插入图片描述

每个模块脚本都会生成一个编译模块任务,在评估之前编译其内容。

模块编译完成后,随后在其中运行的任何代码都标记为Evaluate module tasks

在这里插入图片描述

从上图可以看见使用type=module需要承担一些不可避免的成本。虽然我们应该努力提供尽可能少的 JavaScript,但使用 ES 模块(无论浏览器如何)都可以提供以下好处:

  • 所有模块代码都会在严格模式下自动运行,这允许 JavaScript 引擎进行潜在的优化,而这些优化在非严格上下文中是无法实现的。
  • 使用type=module属性在加载时会默认当作为defer。可以在ES加载的脚本上使用设置async来更改此行为。

基于Safari 和 Firefox 的浏览器

当在 SafariFirefox 中加载type=module模块时,每个模块都会在单独的任务中进行评估。这意味着理论上我们可以将仅包含静态import语句的单个顶级模块加载到其他模块中,并且加载的每个模块都会产生单独的网络请求和任务来进行评估。

使用动态import()

动态import()是加载脚本的另一种方法。import与需要位于 ES 模块顶部的静态语句不同,动态import()调用可以出现在脚本中的任何位置,以按需加载 JavaScript 块。这种技术称为代码分割。

使用动态import()有两个好处:

  1. 推迟加载的模块(设置defer)通过减少当前加载的 JavaScript 量来减少启动期间的主线程争用。这释放了主线程,因此它可以更好地响应用户交互。
  2. 当进行动态import()调用时,每次调用都会有效地将每个模块的编译和评估分离到自己的任务中。当然,import()加载非常大的模块的动态将启动相当大的脚本评估任务,并且如果交互与动态调用同时发生,import()则可能会干扰主线程响应用户输入的能力。因此,加载尽可能少的 JavaScript 还是非常重要的。

动态import()调用在所有主要浏览器引擎中的行为都类似:结果的脚本评估任务将与动态导入的模块数量相同。

在web worker中加载js

Web Worker是一个特殊的 JavaScript 用例。Web Worker 在主线程上注册,然后 Worker 中的代码会在自己的线程上运行。这可以减少主线程拥塞,并有助于保持主线程对用户交互的响应更加灵敏。

除了减少主线程工作之外,Web Worker本身还可以importScripts或者静态import来加载外部js,这样通过 Web Worker 请求的任何脚本都会在主线程之外进行评估。

总结

虽然将脚本分解为单独的较小文件有助于限制长时间任务,但是在决定如何分解脚本时也需要考虑以下几点:

压缩效率

压缩是分解脚本的一个因素。当脚本较小时,压缩效率会有所降低。较大的脚本将从压缩中受益更多。虽然提高压缩效率有助于尽可能缩短脚本的加载时间,但确保将脚本分解为足够小的块以在启动期间促进更好的交互性也是需要权衡决定的。

打包工具是一个非常理想的工具,可以用来管理我们的js打包结果:

  • 比如说webpack,可以通过SplitChunksPlugin插件来管理打包后的js的大小。
  • 对于Rollupesbuild而言,可以通过在代码中使用动态import()来管理脚本文件大小。这些打包工具会自动将动态import()的资源分解到其他的文件中,从而避免生成较大的文件。

缓存

缓存对于一些需要重复访问时页面加载的速度起着重要作用。当我们的js包非常大时,每次更新,之前的一些打包文件都会失效(多个文件都打包在一个js文件里,当修改里边的一些代码时,整个打包文件都是更新过的),必须要重新下载。

通过分解脚本,我们不仅可以将脚本评估工作分解为较小的任务,还可以让用户尽量从浏览器的缓存中获取之前的页面内容,而不是需要重新下载文件。这意味着整体页面加载速度更快。

为了使缓存既高效又可以避免从缓存中提供过时的资源,可以在打包出的文件设置哈希值作为文件名。

嵌套模块和加载性能

我们要是在生产环境中使用 ES 模块并使用type=module属性加载它们,则需要了解模块嵌套如何影响启动时间。模块嵌套是指一个 ES 模块静态导入另一个 ES 模块,而另一个 ES 模块又静态导入另一个 ES 模块:

// a.js
import {b} from './b.js';// b.js
import {c} from './c.js';

如果这些模块没有被打包在一起,那么就会导致生成一个请求链:当一个script元素中包含了a.js的代码的时候,就会发送一个请求去请求b.js文件,然后b.js文件又会发送一个请求去请求c.js文件。这种情况下除了修改代码将这些打包在一起外,还可以通过 modulepreload方式提前预加载 ES 模块以避免网络请求链(仅支持基于 Chromium 的浏览器).

相关文章:

js加载和长任务

js加载和长任务 本文将讲解以下浏览器如何加载js&#xff0c;并介绍一些可以提高网页加载速度的方法。 Evaluate Script 如果我们在devtools的performance中分析过网站的加载性能&#xff0c;可能会看到一个很长的任务&#xff0c;叫做Evaluate Script. 在这种情况下&#x…...

利用Stable diffusion Ai 制作艺术二维码超详细参数和教程

大家有没有发现最近这段时间网上出现了各种各样的AI艺术二维码&#xff0c;这种二维码的出现&#xff0c;简直是对二维码的“颠覆式创新”&#xff0c;直接把传统的二维码提升了一个维度&#xff01;作为设计师的我们怎么可以不会呢&#xff1f; 今天就教大家怎么制作这种超有艺…...

【C语言课程设计】图书管理系统

引言&#xff1a; 图书管理系统是一个重要的信息管理系统&#xff0c;对于图书馆和书店等机构来说&#xff0c;它能够方便地管理图书的录入、显示、查询、修改和删除等操作。本实验基于C语言开发了一个简单的图书管理系统&#xff0c;通过账户名和密码进行系统访问和权限控制&a…...

在 ArcGIS Pro 中使用 H3 创建蜂窝六边形

H3是Uber开发的分层索引系统,它使用六边形来平铺地球表面。H3在二十面体(一个具有20个三角形面和12个顶点的形状)上构建其六边形网格。由于仅用六边形不可能平铺二十面体,因此每个分辨率需要12个五边形来完成网格。分层索引网格意味着每个六边形都可以细分为子单元六边形。…...

创建Electron项目

一、使用vite 构建 electron项目 npm init vitelatest Need to install the following packages:create-vitelatest Ok to proceed? (y) y √ Project name: ... CertificateDownload √ Package name: ... certificatedownload √ Select a framework: Vue √ Select a var…...

Spring Boot实践一

一、Spring Boot简介 Spring Boot是一个基于Spring框架的快速开发应用程序的工具。它提供了一种快速、方便的方式来创建基于Spring的应用程序&#xff0c;而无需繁琐的配置。Spring Boot通过自动配置和约定大于配置的方式&#xff0c;使得开发者可以更加专注于业务逻辑的实现&…...

简单认识NoSQL的Redis配置与优化

文章目录 一、关系型数据库与非关系型数据库1、关系型数据库&#xff1a;2、非关系型数据库3、关系型数据库和非关系型数据库区别&#xff1a;4、非关系型数据库应用场景 二.Redis1、简介2、优点&#xff1a;3、Redis为什么这么快&#xff1f; 三、Redis 安装部署1、安装配置2、…...

开发一个RISC-V上的操作系统(二)—— 系统引导程序(Bootloader)

目录 文章传送门 一、什么是Bootloader 二、简单的启动程序 三、上板测试 文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二&#xff09;—— 系统引导…...

Git安装与学习

Git学习网站 Git安装教程 镜像网站 https://registry.npmmirror.com/binary.html 镜像下载是网站对服务器的一个保护措施之一&#xff0c;就是A站点下载的数据同 B站点下载的数据完全一样&#xff0c;b站点就是A站点的一面镜子。 所以镜像下载下来和原站点一摸一样。...

【Docker】docker中容器之间通信方式

文章目录 1. Docker容器之间通信的主要方式1.1 通过容器ip访问1.2. 通过宿主机的ip:port访问1.3. 通过link建立连接&#xff08;官方不推荐使用&#xff09;1.4. 通过 User-defined networks&#xff08;推荐&#xff09; 2. 参考资料 1. Docker容器之间通信的主要方式 1.1 通…...

算法-归并排序-JAVA

下面是Java实现归并排序的示例代码&#xff1a; public class MergeSort {public void mergeSort(int[] arr) {if (arr null || arr.length < 1) {return;}int[] temp new int[arr.length];mergeSort(arr, temp, 0, arr.length - 1);}private void mergeSort(int[] arr, …...

Flask 进阶

Flask 如何访问项目以外的文件 在工作中&#xff0c; 要在项目里展示一些额外的文件&#xff0c; 包括但不限于静态的html。图片&#xff0c; log&#xff0c; 其他的都还好说&#xff0c; 但是当html的时候我就开始犯难了&#xff0c; 因为数量过多 我并不想把它塞进我项目的t…...

home-assistant整合sso

其他软件都可以通过nginx直接做代理添加鉴权&#xff0c;但是这个hass果然是用户安全隐私很强&#xff0c;做代理需要配置白名单&#xff0c;而且支持的三方鉴权都不太适合我的需求&#xff0c;非要改源码才行&#xff0c;后来我发现不用改源码的折中方式 参考文章 External …...

Ip-Limit: 轻量级注解式IP限流组件(二)

author: van , ggfanwentaogmail.comIp-Limit-Example: 轻量级注解式IP限流组件使用样例 项目简介 该项目为ip-limiter的使用示例项目。 ip-limiter地址&#xff1a; https://github.com/DDAaTao/ip-limiter 示例项目文件树 └─example├─handler│ └─BaseException…...

【C++】开源:Redis数据库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍Redis数据库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c…...

TCP/IP网络编程 第二十四章:制作HTTP服务器端

实现简单的Web服务器端 现在开始在HTTP协议的基础上编写Web服务器端。先给出Windows平台下的示例&#xff0c;再给出Linux下的示例。在这里我假设各位都有了有关HTTP的知识&#xff0c;如果不知道HTTP协议的具体内容可以参考的往期博客&#xff0c;有了这些基础就不难分析源代…...

React 前端应用中快速实践 OpenTelemetry 云原生可观测性(SigNoz/K8S)

OpenTelemetry 可用于跟踪 React 应用程序的性能问题和错误。您可以跟踪从前端 web 应用程序到下游服务的用户请求。OpenTelemetry 是云原生计算基金会(CNCF)下的一个开源项目&#xff0c;旨在标准化遥测数据的生成和收集。已成为下一代可观测平台的事实标准。 React(也称为 Re…...

Linux 多线程并发Socket服务端的实现( 11 ) -【Linux通信架构系列 】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythi…...

2.7. Java 泛型了解么?什么是类型擦除?介绍一下常用的通配符?

Java 泛型&#xff08;generics&#xff09;是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制&#xff0c;该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型&#xff0c;也就是说所操作的数据类型被指定为一个参数。 Java 的泛型是伪泛型&am…...

单例模式与构造器模式

单例模式 1、是什么 单例模式&#xff08;Singleton Pattern&#xff09;&#xff1a;创建型模式&#xff0c;提供了一种创建对象的最佳方式&#xff0c;这种模式涉及到一个单一的类&#xff0c;该类负责创建自己的对象&#xff0c;同时确保只有单个对象被创建 在应用程序运…...

SQL力扣练习(七)

1.行程和用户(262) 表&#xff1a;Trips ----------------------- | Column Name | Type | ----------------------- | id | int | | client_id | int | | driver_id | int | | city_id | int | | status | enum | | reques…...

C语言假期作业 DAY 05

题目 一、选择题 1、如下程序的功能是&#xff08; &#xff09; #include <stdio.h> int main() { char ch[80] "123abcdEFG*&"; int j; puts(ch); for(j 0; ch[j] ! \0; j) if(ch[j] > A && ch[j] < Z) ch[j] ch[j] e - E; puts(ch)…...

php-golang-rpc使用roadrunner-server/goridge/v3/pkg/rpc和php的spiral/goridge3.2实践

golang代码&#xff1a; go get github.com/roadrunner-server/goridge/v3 package main import ( "fmt" "net" "net/rpc" goridgeRpc "github.com/roadrunner-server/goridge/v3/pkg/rpc" ) type App struct{} func (s *App) Hi(na…...

API常用签名验证方法(PHP实现)

使用场景 现在越来越多的项目使用的前后端分离的模式进行开发&#xff0c;后端开发人员使用API接口传递数据给到前端开发进行处理展示&#xff0c;在一些比较重要的修改数据接口&#xff0c;涉及金钱&#xff0c;用户信息等修改的接口如果不做防护验证&#xff0c;经常容易被人…...

kotlin高阶函数

kotlin高阶函数 函数式API:一个函数的入参数为Lambda表达式的函数就是函数式api 例子: public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {return filterTo(ArrayList<T>(), predicate) }上面这段函数: 首先这个函…...

kotlin list集合树

kotlin list集合树 记录一下 data class AreaSchemaManageDto(var id: Long? null,var pid: Long? null,var label: String? null,var children: MutableList<AreaSchemaManageDto>? null ) : Serializable { }逻辑 fun getAll(): List<AreaSchemaManageDto&g…...

基于Autoencoder自编码的64QAM星座图整形调制解调通信系统性能matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1星座图整形 4.2自编码器 4.3基于Autoencoder的星座图整形调制解调模型 4.4 实现过程 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .…...

【Spring】Spring 总览

一、简单介绍一下 Spring Spring是一个全面的、企业应用开发的一站式解决方案&#xff0c;贯穿表现层、业务层、持久层&#xff0c;可以轻松和其他框架整合&#xff0c;具有轻量级、控制反转、面向切面、容器等特征。 轻量级 &#xff1a; 空间开销和时间开销都很轻量 控制反…...

微软、OpenAI用上“数据永动机” 合成数据是晨曦还是暮光?

微软、OpenAI、Cohere等公司已经开始测试使用合成数据来训练AI模型。Cohere首席执行官Aiden Gomez表示&#xff0c;合成数据可以适用于很多训练场景&#xff0c;只是目前尚未全面推广。 已有的&#xff08;通用&#xff09;数据资源似乎接近效能极限&#xff0c;开发人员认为&a…...

简单认识Redis 数据库的高可用

文章目录 一、Redis 高可用&#xff1a;1.简介&#xff1a;2、在Redis中实现高可用的技术 二、Redis持久化&#xff1a;1.持久化的功能&#xff1a;2.Redis 提供两种方式进行持久化&#xff1a; 三、RDB 持久化&#xff1a;1.简介&#xff1a;2.触发条件&#xff1a;4.启动时加…...