第十六章-运行环境

运行环境

  • 运行环境即浏览器(server端有node.js)
  • 下载网页代码,渲染出页面,期间可能会执行若干 JS 逻辑
  • 要保证代码在浏览器中:稳定且高效
  • 了解网页的加载过程
  • 性能优化和体验优化
  • 安全问题

网页加载过程

题目:

  • 从输入 url 到渲染出页面的整个过程
  • window.onload 和 DOMContentLoaded 的区别

知识点:

  • 加载资源的形式
  • 加载资源的过程
  • 渲染页面的过程

资源的形式

  • html 代码
  • 媒体文件,如图片、视频等
  • javascript、css

加载过程

  • DNS 解析: 将域名解析为 ip 地址
  • 浏览器根据 IP 地址向服务器发起 http 请求(三次握手)
  • 服务器处理 http 请求,并返回给浏览器

渲染过程1

  • 根据 HTML 代码生成 DOMTree
  • 根据CSS代码生成 CSSOM
  • 将DOM Tree 和 CSSOM 整合形成 Render Tree

渲染过程2

  • 根据 Render Tree 渲染页面
  • 遇到 <script> 则暂停渲染(js代码中可能会有改变页面内容的操作),优先加载并执行 JS 代码,完成JS之后继续
  • 直到把 Render Tree 渲染完成

为什么建议把 css 放在 head 中?

DOM Tree 从上到下执行,如果 css 没有放到头部,而是放到了尾部,会先 DOM 结构渲染出来而没有样式,直到遇到 css 才会将 css 与 DOM tree 结合

为什么建议把 js 放在 body 最后?

js代码会阻塞页面的渲染

window.onload 和 DOMContentLoaded 的区别

// 页面的全部资源加载完后才会执行,包括图片、视频等
window.addEventListener('load', function () {

})

// DOM 渲染完成即可执行,此时图片、视频还可能没有加载完成
document.addEventListener('DOMContentLoaded', function () {
  
})

性能优化的方式

性能优化是一个综合性问题,没有标准答案,但要求尽量全面,某些细节问题可能会单独提问:手写防抖、节流

性能优化原则

  • 多使用内存、缓存或者其他方法
  • 减少 CPU 计算量,减少网络加载耗时
  • 适用于所有的编程的性能优化 -- 空间换时间(每个标签页放一个进程)

从何入手

  • 让加载更快
  • 让渲染更快

让加载更快

  • 减少资源体积:压缩代码(webpack、gulp)。gzip(服务端压缩)
  • 减少访问次数:合并代码(webpack),SSR服务端渲染,缓存,精灵图
  • 使用更快的网络:CDN(内容分发网络)

让渲染更快

  • CSS 放在 head, JS 放在 body 最下面
  • 尽早开始执行 JS, 用 DOMContentLoaded 触发
  • 懒加载(图片懒加载,上滑/下拉加载更多)
  • 对 DOM 查询进行缓存
  • 频繁 DOM 操作,合并到一起插入 DOM 结构
  • 节流 throttle 防抖 debounce

示例讲解

缓存:配置 webpack 压缩时 hash 值,根据文件内容计算 hash 值。文件内容不变,则hash 不变,则 url 不变。url 和文件不变,则会自动触发 http 缓存机制,返回 304(资源未被修改,可以使用本地缓存)

SSR:(SSR)服务端渲染,将网页和数据一起加载,一起渲染;非SSR(前后端分离),先加载网页,再加载数据,然后渲染数据。早先的 JSP ASP PHP,现在 Vue React SSR。

懒加载:

<img id='img' src="loading.png" data-realsrc="read.png" />
<script>
  let img1 = document.getElementById('img1')
  img1.src = img1.getAttribute('data-realsrc')
</script>

手写防抖(debounce)

  • 监听一个输入框,文字变化后触发 change 事件
  • 直接用 keyup 事件,则会频繁触发 change 事件
  • 防抖:用户输入结束或者暂停时,才会触发 change 事件
const input1 = document.getElementById('input1')
let timer = null
input1.addEventListener('keyup',function () {
  if (timer) {
    clearTimeout(timer)
  }
  timer = setTimeout(() => {
    // 模拟触发 change 事件
	console.log(iput1.value)
    // 清空定时器
    timer = null
  }, 500)
})


封装防抖函数

// 封装防抖函数
function debounce(fn, delay = 500) {
	// timer 是闭包中的
  let timer = null
  // 返回一个函数
  return function () {
    if (timer) {
		clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn.apply(this, arguments)
      timer = null
    }, delay)
  }
}

input1.addEventListener('keyup', debounce(function () {
  console.log(input1.value)
}, 500))

手写节流(throttle)

  • 拖拽一个元素时,要随时拿到该元素被拖拽的位置
  • 直接用 drag 事件,则会频繁触发,很容易导致卡顿
  • 节流:无论拖拽速度多快,都会每隔一段时间触发(100ms)
const div1 = document.getElementById('div1')

let timer = null
div1.addEventListener('drag', function (e) {
  if (timer) {
    return
  }
  timer = setTimeout(() => {
    console.log(e.offsetX, e.offsetY)
    
    timer = null
  }, 100)
})

封装节流函数

function throttle(fn, delay = 100) {
	let timer = null
    
    return function () {
      if (timer) {
        return
      }
      timer = setTimeout(() => {
        fn.apply(this, arguments)
        timer = null
      }, delay)
    }
}

div1.addEventListener('drag', throttle(function (e) {
  console.log(e.offsetX, e.offsetY)
}, 100))

安全

问题:常见的web前端攻击方式有哪些?

  • XSS 跨站请求攻击
  • XSRF 跨站请求伪造

XSS 攻击

  • 一个博客网站,我发表一篇博客,其中嵌套 <script> 脚本
  • 脚本内容:获取cookie,发送到我的服务器(服务器配合跨域)
  • 发布这篇博客,有人查看它,我轻松收割访问者的 cookie

XSS 预防

  • 替换特殊字符,如 < 变为 &lt;> 变为 &gt;
  • <script> 变为 &lt;script&gt;,直接显示不会作为脚本执行
  • 前端要替换,后端也要替换,都做总不会有错
  • npm 有个 xss 预防攻击的包

XSRF 攻击

  • 你正在购物,看中了某个商品,商品id是100
  • 付费的接口是 xxx.com/pay?id=100
  • 我是攻击者,我看中了一个商品,id 是 200
  • 我向你发送一封电子邮件,邮件标题很吸引人
  • 但邮件正文中隐藏着 <img src='xxx.com/pay?id=200'>
  • 你一查看邮件,就帮我购买了 id 是200的商品

XSRF攻击预防

  • 使用 post 接口
  • 增加验证,例如密码、短信验证码、指纹等
  • 不常发生
posted @ 2020-08-07 23:18  公瑾当年  阅读(316)  评论(0编辑  收藏  举报