前端面试题9--运行环境/性能优化

156 阅读4分钟

页面加载过程

加载资源的形式:

  • html代码
  • 媒体文件,如图片、视频等
  • javascript css 加载资源的过程:
  • DNS 解析:域名 -> IP 地址
  • 浏览器根据 IP 地址向服务器发起 http 请求
  • 服务器处理 http 请求,并返回给浏览器 渲染过程:
  • 根据 HTML 代码生成 DOM Tree (文档对象模型)
  • 根据 CSS 代码生成 CSSOM(css对象模型)
  • 将 DOM Tree 和 CSSOM 整合形成 Render Tree(渲染树)
  • 根据 Render Tree 渲染页面
  • 遇到 script 则暂停渲染,优先加载并执行 JS 代码,完成再继续
  • 直至把 Render Tree 渲染完成 (建议把 css 放在 head 中,js 放在 body 最后)

    window.onload 和 DOMContentLoaded:
  • window.onload 资源全部加载完才能执行,包括图片
  • DOMContentLoaded DOM渲染完成即可,图片可能尚未下载
window.addEventListener('load', function () {
    // 页面的全部资源加载完才会执行,包括图片、视频等
})
document.addEventListener('DOMContentLoaded', function () {
    // DOM 渲染完即可执行,此时图片、视频还可能没有加载完
})

性能优化

性能优化原则:

  • 多使用内存、缓存或其他方法
  • 减少 CPU 计算量,减少网络加载耗时
  • (适用于所有编程的性能优化 — 空间换时间) 从何入手:
  • 让加载更快
  • 让渲染更快 让加载更快:
  • 减少资源体积:压缩代码
  • 减少访问次数:合并代码,SSP服务器端渲染,缓存
  • 使用更快的网络:CDN(根据区域做服务器处理) 让渲染更快:
  • CSS 放在 head,JS 放在 body 最下面
  • 尽早开始执行JS,用 DOMContentLoaded 触发
  • 懒加载(图片懒加载,上滑加载更多)
  • 对 DOM 查询进行缓存
  • 频繁 DOM 操作,合并到一起插入 DOM 结构
  • 节流 throttle、 防抖 debounce 缓存:
  • 静态资源加 hash 后缀,根据文件内容计算 hash
  • 文件内容不变,则 hash 不变,则 url 不变
  • url 和文件不变,则会自动触发 http 缓存机制,返回 304 SSR:
  • 服务端渲染:将网页和数据一起加载,一起渲染
  • 非 SSR(前后端分离):先加载网页,再加载数据,再渲染数据 懒加载、缓存DOM查询、多个DOM操作一起插入到DOM结构、尽早开始JS执行用DOMContentLoaded

防抖 debounce

  • 监听一个输入框的,文字变化后触发change事件
  • 直接用keyup事件,则会频发触发change事件
  • 防抖:用户输入结束或暂停时,才会触发change事件
const input1 = document.getElementById('input1')
const timer = null
input1.addEventListener('keyup',function () {
    if (timer) {
        clearTimeout(timer)
    }
    timer = setTimeout(() => {
        // 模拟触发 change 事件
        console.log(input1.value)
        // 清空定时器
        timer = null
    }, 500)
})
// 防抖
function debounce (fn, delay = 500) {
    // timer 是闭包中的,闭包在函数作为返回值或者函数作为参数时使用
    let timer = null
    return function () {
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
            fn()
            timer = null
        },delay)
    }
}
input1.addEventListener('keyup', debounce(() => {
    // 执行函数
}),600)

// 防抖
function debounce (fn, delay = 500) {
    // timer 是闭包中的,闭包在函数作为返回值或者函数作为参数时使用
    let timer = null
    return function () {
        if (timer) {
            clearTimeout(timer)
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments) // 使用apply就不能用箭头函数;传参需要用apply
            timer = null
        },delay)
    }
}
input1.addEventListener('keyup', debounce(function (e) {
    // 执行函数
    conso.log(e.target)
    console.log(input1.value)
}),600)

节流 throttle

  • 拖拽一个元素时,要随时拿到该元素被拖拽的位置
  • 直接用 drag 事件,则会频发触发,很容易导致卡顿
  • 节流:无论拖拽速度多快,都会每隔 一段时间(如100ms)触发一次
<div id="div1" draggable="true">可拖拽</div>
// 节流
function throttle(fn, delay = 100) {
    let timer = null
    return function () {
        if (timer) {
            return
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments) // (绑定this, 绑定参数)
            timer = null
        })
    }
}
div1.addEventListener('drag', throttle(function (e) {
    // 函数体
    console.log(e.offsetX, e.offsetY)
}, 200))

安全—常见的web前端攻击方式

  • XSS 跨站攻击
  • XSRF 跨站攻击 XSS 攻击:
  • 一个博客网站,我发表一篇博客,其中嵌入script脚本
  • 脚本内容:获取 cookie ,发送到我的服务器(服务器配合跨域)
  • 发布这篇博客,有人查看它,我轻松收割访问者的cookie XSS 预防:
  • 替换特殊字符,如 < 变为 < > 变为 >
  • <script> 变为 &lt;scripe&gt;,直接显示,而不会作为脚本执行
  • 前端要替换,后端也要替换,都做总不会有错 XSRF 攻击:
  • 你正在购物,看中了某个商品,商品id是100
  • 付费接口是 xxx.com/pay?id=100,但没有任何验证
  • 我是攻击者,我看中一个商品,id是200
  • 我向你发送一封电子邮件,邮件标题很吸引人
  • 但邮件正文隐藏这 <img src=xxx.com/pay?id=200/>
  • 你一查看邮件,就帮我购买了id是200的商品 XSRF 预防:
  • 使用 post 接口
  • 增加验证,例如 密码、短信验证码、指纹等