你的应用太慢了,给我司带来了巨额损失,该怎么办

记得很久之前看过谷歌官方有这么样的声明:如果一个页面的加载时间从 1 秒增加到3 秒,那么用户跳出的概率将增加 32%。

但是早在 2012 年,亚马逊就计算出了,页面加载速度一旦下降一秒钟,每年就会损失 16 亿美元的销售额。于是,这篇文章就想聊聊有没有方法来解决这种问题。

什么?没赚到钱,是我的锅?

那么,是什么影响了页面的加载速度,导致用户跳出?

其中有一个大的因素就是我们的应用用到了很多的第三方库。

那么,有没有一种一举两得的方法,我即可以保留使用的第三方脚本,又可以保证页面的加载速度?

其实,我们知道 JavaScript 本质上是一种单线程语言,只运行一个事件循环。这意味着一次只执行一条语句。由于这一限制,当试图运行自己的代码以及任何第三方脚本时,它们必须在同一线程中执行。这意味着由于处理能力的限制,它们会减慢主线程和彼此的速度,也会减慢彼此的速度。

根据谷歌的说法,添加第三方脚本后,有一些潜在的问题会产生,我列举了以下几点:

  • 会向多个服务器发出过多的网络请求。一个网站的请求越多,它的加载时间就越长。
  • 发送太多的 JavaScript 会让主线程很忙。过多的 JavaScript 会阻碍 DOM 的构建,延迟页面呈现的速度
  • cpu 密集型脚本解析和执行可能会延迟用户交互,并会导致电池电量消耗的更快。
  • 不小心加载的第三方脚本可能会产生单点故障(SPOF)。
  • HTTP 缓存不足,迫使经常直接从网络获取资源。
  • 脚本中使用遗留 api(例如 document.write() ),对用户体验是有害的。
  • 脚本中包含过多的 DOM 元素或昂贵的 CSS 选择器。
  • 包括多个第三方嵌入,可能导致多个框架和库被多次拉入,这加剧了性能问题。
  • 第三方脚本也经常使用嵌入技术导致阻塞 window.onload 的执行,例如使用 async或 defer

这些问题都可以通过谷歌浏览器的 Analytics 工具检测出来。

现在,有一个改善第三方脚本的工具,能帮助我们的应用减少大量的第三方脚本,也是本篇文章要说的主角—— Partytown

Partytown

Partytown 是一个 JavaScript 库,可以让你的第三方脚本交给 web worker 来处理,以消除他们可能对你的网站产生的性能影响。为了抵消上述第三方脚本的负面影响,Partytown 打算做以下事情:

  • 释放主线程资源,仅用于主要 web 应用程序的执行。
  • 将第三方脚本放到沙箱,允许或拒绝它们访问主线程 api。
  • 在 web worker 线程中隔离长时间运行的任务。
  • 通过将 DOM setter /getter 批处理到组更新中,减少来自第三方脚本的布局抖动。
  • 限制第三方脚本对主线程的访问。
  • 允许第三方脚本完全按照它们的编码方式运行,无需任何更改。
  • 在 web worker 中同步读写主线程 DOM 操作,允许在 web worker 中运行的脚本按预期执行。

Partywork 运行方式

简单地说,Partytown 添加了一个 worker 线程来允许在主线程和 worker 线程中执行

要理解 Partytown,首先要了解现代网络浏览器使用的一些技术:

  • Web Workers API: 这使得在与 Web 应用程序的主执行线程分离的后台线程中运行脚本操作成为可能。Partytown 的理念是主线程应该专门用于你的第一方代码任何不需要在关键路径上的脚本都应该移动到 web worker上。因为主线程的性能比 web worker 线程的性能更重要。
  • XMLHttpRequest (XHR): 对象用于与服务器交互。可以从URL检索数据,而不必进行整个页面刷新。这使得网页只更新页面的一部分,而不会中断用户正在做的事情。
  • Service Worker API: Service Worker 本质上充当了位于 web 应用程序、浏览器和网络之间的代理服务器。它们主要用于创建有效的脱机体验,拦截网络请求,并根据网络是否可用采取适当的操作,以及更新驻留在服务器上的资源。它们还允许访问推送通知和后台同步 api。
  • Javascript 代理:代理对象允许你创建一个可以用来代替原始对象的对象,但它可能会重新定义基本的对象操作,如 get、set 和 define 属性。代理对象通常用于记录属性访问、验证、格式化或清除输入等。

传统上,主线程和 worker 线程之间的通信必须是异步的:因为为了让两个线程通信,它们不能使用阻塞调用。Partytown 则不同。它允许从 web worker 执行的代码同步访问 DOM这样做的好处是第三方脚本可以继续按照它们的编码方式工作。

如下图所示,运行在代理全局变量的 web worker 中的代码使用同步 XHR 使异步操作同步化。这将被 service worker 拦截,主线程值将通过 postMessage 检索并发送回来。

在这里插入图片描述

如何集成 Partytown

你可以很容易地将它添加到任何站点,并使用 type="text/partytown" 标记任何你想要加载在 web worker 中的脚本。

需要注意的是,Partytown 并不会自动将所有脚本转移到 web worker上,而是采用了一种可选择的方法最好的情况是,开发人员可以准确地选择哪些脚本应该使用Partytown,而所有其他脚本将保持不变。

Partytown可以使用任何 HTML 页面,不需要特定的框架。然而,为了让它更容易在各种框架或服务中使用,可以为它们的生态系统制作插件/包装器。

只有当特定脚本具有 type="text/ Partytown " 属性时,才会启用 Partytown。

<script type="text/partytown" src="third-parth.js"></script>

上面这段脚本执行时会产生几个事件:

  • 通过使用 <script/>标签上的 type="text/partytown" 属性,脚本不能在主线程上运行。
  • Service worker 创建一个 “onfetch” 处理程序来拦截特定的请求。
  • Web worker 会处理在 worker 线程中执行的脚本。
  • Web worker 创建 JavaScript 代理来复制和转发对主线程 api 的调用(比如DOM操作)。
  • 任何对JavaScript 代理的调用都使用同步XHR请求。
  • Service worker 拦截请求,然后能够与主线程进行异步通信
  • 当 Service worker 从主线程接收到结果时,它会响应 web worker 的请求。
  • 从在 web worker 上执行代码的角度来看,一切都是同步的,对 document 的每次调用都是阻塞的。

执行步骤

任何你添加 type="text/partytown" 的脚本都会在默认情况下加载到 web worker 中,但是可以完全访问全局变量。' type="text/partytown" ' 属性做两件事:

  1. 通知浏览器不处理脚本。通过给脚本一个浏览器无法识别的 type 属性:“嵌入的内容被视为一个数据块,浏览器不会处理它。”
  2. 提供一个 query 选择器,这样 Partytown 就可以找到所有要在web worker中运行的脚本。当 document 准备好并且 Partytown 已经初始化时,Partytown 将查询所有脚本属性中含有 [type="text/ Partytown "] 属性的元素。你会注意到,当一个脚本在web worker中执行后,它会得到一个更新的 type 属性: type="text/partytown-x"
// run in the worker
fetch('/track', {
	body: JSON.stringify({
		url: window.location.href // run on the main thread
	})
})

我们使用 JavaScript Proxy 向 worker 线程提供主线程全局变量,拦截它们并转发给主线程:

self.window = new Proxy({
  get(key) {
  	return getFromMainThread(key)
  }
})

这里是最好的部分是: 使用一个同步 XHR 请求来阻塞 worker 线程,并从主线程检索所需的值:

function getFromMainThread(prop) {
	request.open('POST', '/proxytown', false)
	request.send(null)
	request.send(JSON.stringify({prop}))
	return JSON.parse(request.reponseText)
}

现在我们可以使用 service worker 来拦截 /proxytown 请求,向主线程异步postMessage 以获取所需的值并返回它:

self.addEventListener('fetch', event=>{
	if(request.url === '/proxytown') {
		event.respondWith(new Promise(async resolve=>{
			resolve(await getFromMainThread(event.request.json()))
		}))
	}
})

好了!你现在可以无缝地将一系列第三方脚本放到 web worker 中运行,从而消除主线程的性能成本。如果感兴趣,可以用一用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/3648.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

杨辉三角形 (蓝桥杯) JAVA

目录题目描述&#xff1a;暴力破解&#xff08;四成&#xff09;&#xff1a;二分法破解&#xff08;满分&#xff09;&#xff1a;题目描述&#xff1a; 下面的图形是著名的杨辉三角形&#xff1a; 如果我们按从上到下、从左到右的顺序把所有数排成一列&#xff0c;可以得到如…

如何编写测试用例?

带着问题学习是最高效的学习方法。 因此&#xff0c;在介绍如何编写测试用例之前&#xff0c;先看一个软件系统登录功能的测试&#xff08;如下截图所示&#xff09;&#xff1a; 要做这个登录页面的测试用例&#xff0c;你会从哪些方面思考进行测试呢&#xff1f; 看似简单的…

【C语言蓝桥杯每日一题】—— 货物摆放

【C语言蓝桥杯每日一题】—— 货物摆放&#x1f60e;前言&#x1f64c;排序&#x1f64c;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01;&#xff01;&#xff01; &#x1f60a;作者简介…

图话第一代女性开发者

写在前面的话想问大家一个有趣的问题&#xff0c;大家知道我们程序员圈的第一位女性开发者是谁吗&#xff1f;作为开发者&#xff0c;以前并没有认真去想过这个问题&#xff0c;这两天认真的看了一下百度百科查找了一下相关的专业知识。才知道历史上第一位女性程序员是&#xf…

docker+jenkins+maven+git构建聚合项目,实现自动化部署,走了800个坑

流程 主要的逻辑就是Docker上安装jenkins&#xff0c;然后拉取git上的代码&#xff0c;把git上的代码用Maven打包成jar包&#xff0c;然后在docker运行 这个流程上的难点 一个是聚合项目有可能Maven install的时候失败。 解决办法&#xff1a;在基础模块的pom文件上添加 <…

重谈“协议” + 序列化和反序列化

目录 1、重谈 "协议" 协议的概念 结构化数据的传输 序列化和反序列化 2、网络版计算器 2.1、服务端serverTcp.cc文件 服务端serverTcp.cc总代码 2.2、客户端clientTcp.cc文件 客户端clientTcp.cc总代码 2.3、协议定制Protocol.hpp文件 服务端需要的协议 客户端需要…

惠普官网驱动程序与软件下载,如何安装打印机驱动

惠普&#xff08;HP&#xff09;是一家全球知名的计算机硬件制造商&#xff0c;其产品涵盖台式电脑、笔记本电脑、打印机、扫描仪等。为了保证产品的正常运行和最佳性能&#xff0c;惠普为其设备提供了驱动程序和软件的下载服务。本文将介绍如何在惠普官网下载所需的驱动程序和…

【Linux】 基础IO——文件(中)

文章目录1. 文件描述符为什么从3开始使用&#xff1f;2. 文件描述符本质理解3. 如何理解Linux下的一切皆文件&#xff1f;4. FILE是什么&#xff0c;谁提供&#xff1f;和内核的struct有关系么&#xff1f;证明struct FILE结构体中存在文件描述符fd5. 重定向的本质输出重定向输…

Linux基础

环境搭建&#xff1a;linux安装、远程连接常用命令&#xff1a;文件、目录、拷贝、移动、打包、压缩、文本编辑安装软件&#xff1a;文件上传、jdk、tomcat、mysql项目部署&#xff1a;Java应用、Python应用、日志查看、系统管理、用户权限Linux是一套免费使用、自由传播的操作…

ngx之日志切割

正确记日志方式是每天都进行切割重新写&#xff0c;保留固定的时间后可使用 find 删除。 用系统自带有的 logrotate /etc/logrotate.d 下面再建立一个文件&#xff0c;这里是nginx &#xff08; 中途有 ctrlZ 暂停过任务&#xff0c;后面fg恢复的 &#xff09; /usr/local/ng…

不同类型的电机的工作原理和控制方法汇总

电机控制是指对电机的启动、调速&#xff08;加速、减速&#xff09;、运转方向和停止进行的控制&#xff0c;不同类型的电机有着不同的工作原理和控制方法。 一、无刷电机 无刷电机是由电机主体和电机驱动板组成的一种没有电刷和换向器的机电一体化产品。在无刷电机中&#xf…

【leetcode】链表(2)

目录 1. 环形链表 解题思路 2. 环形链表 II 解题思路 3. 删除排序链表中的重复元素 解题思路 4. 删除排序链表中的重复元素 II 解题思路 5. 移除链表元素 解题思路 6. 链表的中间结点 解题思路 1. 环形链表 OJ&#xff1a;环形链表 给你一个链表的头节点 head &am…

第二章 作业(6789B)【编译原理】

第二章 作业【编译原理】前言推荐第二章 作业678911最后前言 以下内容源自《编译原理》 仅供学习交流使用 推荐 无 第二章 作业 6 6.令文法G6为 N→D|ND D→0|1|2|3|4|5|6|7|8|9 (1)G6的语言L(G6)是什么? (2)给出句子0127、34和568的最左推导和最右推导。 &#xff08;…

【开发】后端框架——SpringBoot

title: SpringBoot top: 56 categories: 开发后端框架 tags:开发后端框架SpringBoot abbrlink: 1864766114 date: 2022-03-15 21:49:17 前置知识&#xff1a; Spring Mybatis SpringMVC 学习视频&#xff1a;https://www.bilibili.com/video/BV1PE411i7CV?spm_id_from333.337…

【Linux】进程控制

进程创建fork/vfork1.1.fork函数初识在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。#include <unistd.h> pid_t fork(void); //返回值&#xff1a;自进程中返回0&#xff0c;父进程返回子…

前端实现一个名言生成器

The sand accumulates to form a pagoda✨ 写在前面✨ JS是什么&#xff1f;✨ 名言生成器✨ 页面搭建✨ 功能实现✨ 写在前面 在上周我们通过HTML、CSS实现了一个简单的‘我的相册‘页面的搭建&#xff0c;很多伙伴呢跟我说难道前端就只能做一些页面搭建的工作吗&#xff1f;…

Linux系统编程 - 基础IO(IO操作)

目录 预备知识 复习C文件IO相关操作 printf相关函数 fprintf snprintf 读取文件 系统文件IO操作 open函数 umask()函数 open函数返回值 预备知识 1.你真的理解文件原理和操作了吗&#xff1f;不是语言问题&#xff0c;是系统问题2.是不是只有C/C有文件操作呢&#x…

【Java开发】设计模式 08:组合模式

1 组合模式介绍组合模式是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构&#xff0c;以表示部分-整体的层次结构。组合模式使得客户端可以统一处理单个对象和组合对象&#xff0c;从而简化了客户端代码。在组合模式中&#xff0c;有两种类型的对象&#xff1a;叶子…

【C语言初阶】函数

文章目录&#x1f490;专栏导读&#x1f490;文章导读&#x1f337;函数是什么&#xff1f;&#x1f337;函数的分类&#x1f33a;库函数&#x1f33a;自定义函数&#x1f337;函数的参数&#x1f337;函数的调用&#x1f337;函数的嵌套调用和链式访问&#x1f33a;嵌套调用&a…

小游戏也要讲信用

当下&#xff0c;小游戏鱼龙混杂&#xff0c;官方为能更好地保护用户、开发者以及平台的权益&#xff0c;近日宣布7月1日起试行小游戏主体信用分机制。 主体信用分是什么呢&#xff1f;简单来说&#xff0c;这是针对小游戏主体下所有小游戏帐号行为&#xff0c;对开发者进行评…