记录--浏览器渲染15M文本导致崩溃怎么办
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
最近,我刚刚完成了一个阅读器的txt文件阅读功能,但在处理大文件时,遇到了文本内容过多导致浏览器崩溃的问题。
一般情况下,没有任何样式渲染时不会出现什么问题,15MB的文件大约会有3秒的空白时间。
<div id="content"></div>
fetch('./dp.txt').then(resp => resp.text()).then(text => {
document.getElementById('content').innerText = text
})
尽管目前还没有严重的问题,但随着文件继续增大,肯定会超过浏览器内存限制而导致崩溃。
在开发阅读器的过程中,我添加了下面的样式,结果导致浏览器直接崩溃:
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
overflow: hidden;
}
body {
column-fill: auto;
column-width: 375px;
overflow-x: auto;
}
预期结果应该是像下面这样分段显示:

然而,实际出现了下面的问题:

因此,文件内容太多会导致浏览器崩溃。即使进行普通的渲染,我们也要考虑这个问题。
如何解决
解决这个问题的方法有点经验的前端开发工程师应该都知道可以使用虚拟滚动,重点是怎么对文本分段分段,最容易的可能就是按照一定数量字符划分,但是这个导致文本衔接不整齐出现文本跳动。如图,橙色和蓝色表示两端文本的衔接,虚拟滚动必然会提前移除橙色那块内容,那么就会导致蓝色文本位置发生改变。

要解决这个问题,我们需要想办法用某个元素替代原来的位置。当前页橙色部分删除并计算位置,问题会变得复杂并且误差比较大,因此这一部分直接保留,把这部分前面的内容移除,然后用相同长度的元素占据,接下来重点就是怎么获取到橙色部分与前面内容的分界点。
获取分界点可以使用document.createRange(),document.createRange()是 JavaScript 中用于创建Range对象的方法。Range对象表示一个包含节点与文本节点之间一定范围的文档片段。这个范围可以横跨单个节点、部分节点或者多个节点。
// 创建 Range 对象
const range = document.createRange(); range.setStart(textNode, 0); // 第一个参数可以是文本节点,第二个参数表示偏移量
range.setEnd(textNode, 1);
const rect = range.getBoundingClientRect(); // 获取第一个字符的位置信息
利用Range对象的特性,我们可以从橙色部分的最后一个字符开始计算,直到找到分界点的位置。
阅读器如果仅仅只是从左往右阅读,按照上面的方法已经可以实现,但是阅读器可能会出现页面直接跳转,跳转之后的文本起点你并不知道,并且页面总页码你也无法知道。因此从一开始就要知道每一页的分界点,也就是需要做预渲染。以下是一个简单的示例:
let text = '...'
const step = 300
let end = Math.min(step, value.length) // 获取结束点 while (text.length > 0) {
node.innerText = value.substring(0, end) // 取部分插入节点
const range = document.createRange()
range.selectNodeContents(node)
const rect = range.getBoundingClientRect() // 获取当前内容的位置信息 if (rect.height > boxHeight) {
// 判断当前内容高度是否会超出显示区域的高度
// 如果超出,从 end 最后一个字符开始计算,直到不超出范围
while (bottom > boxHeight) {
// node.childNodes[0] 表示文本节点
range.setStart(node.childNodes[0], end - 1)
range.setEnd(node.childNodes[0], end)
bottom = range.getBoundingClientRect().bottom
end--
}
} else {
// 如果没有超出,end 继续增加
// ...
}
}
上面只是简单的实现原理,可以达到精确区分每一页的字符,但是计算量有点太大,15MB文本大约500多万字,循环次数估计也在几十万到上百万。在本人的电脑上测试大约需要20秒,每个人设备的性能不同,所需时间也会有所不同。很明显,这种实现方式并不太理想。
后来我对这个方案进行了优化,实际上我们不需要计算每一页的分界点,可以计算出多页的分界点,例如10页、20页、50页等。优化后的代码是将step增大,比如设为10000,然后将不能组成一页的尾部内容去掉。优化后,15MB的文本大约需要4秒左右。需要注意的是,step并不是越大越好,太大会导致渲染页面占用时间过长。
这就是我目前用来解决页面渲染大量文本的方法。如果你有更好的方案,欢迎留言。
本文转载于:
https://juejin.cn/post/7261231729523965989
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--浏览器渲染15M文本导致崩溃怎么办的更多相关文章
- 【Web动画】CSS3 3D 行星运转 && 浏览器渲染原理
承接上一篇:[CSS3进阶]酷炫的3D旋转透视 . 最近入坑 Web 动画,所以把自己的学习过程记录一下分享给大家. CSS3 3D 行星运转 demo 页面请戳:Demo.(建议使用Chrome打开 ...
- 160826、浏览器渲染页面过程描述,DOM编程技巧以及重排和重绘
一.浏览器渲染页过程描述 1.浏览器解析html源码,然后创建一个DOM树. 在DOM树中,每一个HTML标签都有一个对应的节点(元素节点),并且每一个文本也都有一个对应的节点(文本节点). DO ...
- 浏览器渲染页面过程描述,DOM编程技巧以及重排和重绘。
一.浏览器渲染页过程描述 1.浏览器解析html源码,然后创建一个DOM树. 在DOM树中,每一个HTML标签都有一个对应的节点(元素节点),并且每一个文本也都有一个对应的节点(文本节点). DOM树 ...
- IE (第一部分) 浏览器 中 关于浏览器模式和文本模式的困惑
什么是浏览器模式和文本模式? 经常使用IE开发者工具的同学,肯定见过浏览器模式和文本模式,对于这两个名词,综合相关文档解释如下: 浏览器模式(Browser Mode),用于切换IE针对该网页的默认文 ...
- 从敲入 URL 到浏览器渲染完成、对HTTP协议的理解
1. 大致过程 当你这样子回答的时候: 用户输入 url 地址,浏览器查询 DNS 查找对应的请求 IP 地址 建立 TCP 连接 浏览器向服务器发送 http 请求,如果服务器段返回以 301 之类 ...
- 浏览器渲染详细过程:重绘、重排和 composite 只是冰山一角
https://juejin.im/entry/590801780ce46300617c89b8 渲染 这张很经典的图许多人都看过,其中的概念大家应该都很熟悉,也就是这么几个步骤:js修改dom结构或 ...
- web性能优化-浏览器渲染原理
在web性能优化-浏览器工作原理中讲到,浏览器渲染是在renderer process中完成的. 那我们来看下renderer process究竟干了什么? Renderer Process包含的线程 ...
- iOS开发笔记12:iOS7上UITextField限制字数输入导致崩溃问题
在一些场景中,需要限制用户的输入字数,例如在textField里进行控制(textView也类似,崩溃原因也相同),如图所示 系统会监听文本输入,需要注意的第一点是输入法处于联想输入还未确定提交的时候 ...
- 读书笔记(一)—— 浅析浏览器渲染过程和html中的文件加载
在构建页面时,我们会在html中载入一个或多个css和js文件.或许大家都已经习惯了"最佳实践"中,css文件应该放在<head>标签中引入,而js文件则是放在< ...
- Web标准的简单理解 不同内核浏览器的差异以及浏览器渲染简介(转)
Web标准是一系列标准的集合.这些标准大概分三方面:结构.表现和行为.结构化主要有HTML, XHTML和XML,表现主要有CSS,行为标准主要包括对象模型,如 W3C DOM.ECMAScript等 ...
随机推荐
- [Kafka]Kafka学习 -- 初识Kafka
Kafka学习 -- 初识Kafka 参考资料:稀土掘金<图解Kafka之实战指南>https://juejin.cn/book/6844733793220165639 Kafka是一个多 ...
- [Java][Spring]spring profile与maven profile多环境管理
spring profile 与 maven profile 多环境管理 spring profile Spring profile是Spring提供的多环境管理方案. 如下图: 每种环境都对应一个y ...
- 盘点Java集合(容器)概览,Collection和Map在开发中谁用的最多?
写在开头 在Java的世界里万物皆对象.但我认为是万物皆数据,世界由各种各样数据构建起来,我们通过程序去实现数据的增删改查.转入转出.加减乘除等等,不同语言的实现方式殊途同归.由此可见,数据对于程序语 ...
- JOISC 2018 记录
Day1 T1 Construction of Highway 每一次操作形如查询一条到根的链上的逆序对数,然后将这条链的权值全部修改成同一个权值. 发现这个操作类似于 LCT 的 Access 操作 ...
- 同一份代码怎能在不同环境表现不同?记一个可选链因为代码压缩造成的bug
壹 ❀ 引 某一天,CSM日常找我反馈客户紧急工单,说有一个私有部署客户升级版本后,发现一个功能使用不太正常.因为我们公司客户分为两种,一种是SaaS客户,客户侧使用的版本被动跟随主版本变动,而私有部 ...
- NC23047 华华给月月出题
题目链接 题目 题目描述 华华刚刚帮月月完成了作业.为了展示自己的学习水平之高超,华华还给月月出了一道类似的题: \(Ans=\oplus_{i=1}^N(i^N\mod(10^9+7))\) \(\ ...
- Python中`yield`关键字详解
Python中`yield`关键字有什么用? Python中yield关键字有什么用? 它能做什么? 例如,我试图理解这段代码1: def _get_child_candidates(self, di ...
- Linux查看系统版本的方法
记录几种查看当前Linux系统的版本的方法 一.使用命令:cat /proc/version 查看 linux版本号:Linux version 5.4.0-99-generic (buildd@lg ...
- idea 灵异事件之maven 缓存
方法一 mvn clean install 方法二 强制刷新maven 1 idea 右侧的maven 窗口: 方法三 强制刷新maven 2 右键项目: 上面虽然是重新导入Maven依赖,按理说,I ...
- Optional 详解
1 前言 Optional 是 Java 8 的新特性,专治空指针异常(NullPointerException, 简称 NPE)问题,它是一个容器类,里面只存储一个元素(这点不同于 Conllect ...
