浅谈运行环境:浏览器加载和渲染机制,性能优化,WEB安全

275 阅读5分钟

目标

  • 网页加载过程
  • 常见的性能优化
  • 基本的前端安全预防

JS运行环境

  • 浏览器(server端有Node.js)
  • APP内嵌Web View
    • 例如 微信内嵌浏览器

网页如何加载并渲染出来的

问题:从输入URL到渲染出页面的整个过程 加载过程

  • 浏览器 DNS解析: 通过域名 找到 IP
  • 浏览器 通过IP地址找到发送HTTP请求
  • 服务端处理HTTP请求,并返回浏览器 渲染过程
  • 根据HTML生成DOM Tree
  • 根据CSS生成CSSOM
  • DOM TreeCSSOM整合为Render Tree
  • 当遇到<script>时 停止渲染(因为script中可能会修改Render Tree,渲染没有意义),优先加载并执行JS代码,完成再继续
  • 直到Render Tree渲染完成

CSS 放在head前目的

  • 避免重复渲染
    • 如果放在HTML下面,HTML渲染完后,会加载CSS,假如发现字体不同,会改变字体,导致重复渲染,同时用户可以看到字体变化(不友好)

JS放在最后的目的

  • JS可能会阻断渲染进程,使得页面渲染时间过长

图片加载会暂停渲染过程吗? 不会

  • 因为图片不会改变DOM结构,加载完最多会重排一下
document.addEventListener('DOMContentLoaded', function() {
    // DOM 渲染完即可执行,此时图片、视频还可能没有加载完
})
window.addEventListener('load', function() {
    // 页面的全部资源加载完才会执行,包括图片、视频等
})

性能优化

角度

  • 加载更快
  • 渲染更快 优化原则
  • 多使用内存、缓存等方法(用空间换时间)
  • 减少CPU 计算量,减少网络加载耗时 实现
  • 加载更快
    • 减少资源体积:压缩代码
    • 减少访问次数:合并代码,SSR服务器端渲染,使用缓存
    • 使用更快的网络:CDN(静态 static.com)
  • 让渲染更快
    • CSS放在head里,JS放在body最下面
    • 尽早开始执行JS,用DOMContentLoaded触发
    • 懒加载(图片懒加载,上滑加载更多)
    • 对DOM查询进行缓存
    image.png
    • 频繁操作DOM操作,合并到一起插入ODM结构
    image.png
    • 节流throttle 防抖debounce 例子
  • 缓存
    • webpack打包添加hash的时候,为了通过hash判断文件是否有变化,如果没有变化,命中304,不用重复下载文件
      • hash是根据文件内容计算的,如果文件内容不变,hash不变,url不变
      • url和文件不变,自动触发http缓存机制,返回304
      image.png
  • SSR(服务端渲染:将网页和数据一起加载,一起渲染)
    • 非SSR: 前后端分离 先渲染页面 再加载数据 在渲染数据
    • SSR:JSP ASP PHP

防抖 debounce

应用场景

  • 输入框 不停输入,前后输入间隔大于某个时间,才触发
  • 按钮 多次点击 最后一次才触发
<input id='input1' />
function debounce(fn, delay) {
	let timer;

	return function () {
		if (timer) {
			clearTimeout(timer);
		}

		timer = setTimeout(function() {
                    fn().apply(this, arguments);
                }, delay);
	};
}

document.getElementById("input1").addEventListener("keyup", debounce(function () {
    console.log('keyup')
}, 500));

节流 throttle

无论触发多快,都会每隔一定时间触发一次

应用场景

  • 拖拽元素,获取元素的位置
  • 窗口resize
const throttle = function (fn, delay = 100) {
	let timer = null;
	return function () {
		if (timer) {
			return;
		}
		timer = setTimeout(() => {
			// 不可以用function
			fn.apply(this, arguments);
			timer = null;
		}, delay);
	};
};

// document.getElementById("dragDiv").addEventListener("drag", function (e) { console.log(e.offsetY, e.offsetX); });

document.getElementById("dragDiv").addEventListener(
	"drag",
	throttle(function (e) {
		// 不可以用箭頭函數,因为e是传给throttle返回的函数的,如果没有fn.apply,e.offsetY会报错 ’offsetY‘ of undefined
		console.log(e.offsetY, e.offsetX);
	}, 200)
);

WEB安全

xss攻击

什么是xss攻击

  • xss(Cross-Site Scripting)跨站脚本攻击,是一种代码注入攻击。
    • 通过脚本,获取Cookie,sessionId等敏感信息
  • 分类
    • 存储型
    • 放射型
    • DOM型

预防

  • 需要前端后端同时处理
    • 后端预防 存储型反射型攻击
    • 前端预防 DOM型攻击

      DOM 型 XSS 攻击,实际上就是网站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执行了。

      在使用 .innerHTML.outerHTMLdocument.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent.setAttribute() 等。

      如果用 Vue/React 技术栈,并且不使用 v-html/dangerouslySetInnerHTML 功能,就在前端 render 阶段避免 innerHTMLouterHTML 的 XSS 隐患。

      DOM 中的内联事件监听器,如 locationonclickonerroronloadonmouseover 等,<a> 标签的 href 属性,JavaScript 的 eval()setTimeout()setInterval() 等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。

      
      
      // 1. 链接内包含恶意代码
      <a href="恶意代码" />
      
      // 2. setTimeout/setInterval中调用恶意代码
      
      // 3. location 调用恶意代码
      location.href = '恶意代码'
      
      // 4. eval() 中调用恶意代码
      eval(‘恶意代码’)
      
      // 5. 内联事件监听器 中包含恶意代码
      
  • npm xss工具:www.npmjs.com/package/xss

其他安全措施

  • HTTP-only Cookie: 禁止JavaScript读取某些敏感Cookie
  • 验证码:防止脚本冒充用户提交危险操作

参考:tech.meituan.com/2018/09/27/…

CSRF (Cross-site request forgery)跨站请求伪造

什么是CSRF

攻击者冒充用户对被攻击的网站执行某项操作,例如 转账。

防护策略

CSRF的特点

  • CSRF(通常)发生在第三方域名
  • CSRF攻击者不能获取Cookie等信息,只是使用

根据上面特点制定策略

  • 阻止不明外域的访问
    • 同源检测
    • Samesite Cookie
  • 提交时要求俯角本域才能获取的信息
    • CSRF Token
    • 双重Cookie验证

参考:tech.meituan.com/2018/10/11/…