前端开发环境、运行环境、场景题

本文详细介绍了前端开发的环境配置,包括git、Chrome调试工具、抓包工具的使用,以及webpack和babel的基本配置与性能优化。在运行环境部分,探讨了网页加载过程,浏览器渲染机制,性能优化策略如首屏渲染优化,以及安全防范措施,如防止XSS、CSRF和SQL注入攻击。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

开发环境

 一、webpack、vite、babel

二、git

三、Chrome调试工具

四、抓包

五、linux常用命令

运行环境

一、网页加载过程

1、浏览器从输入URL到页面渲染的整个流程

2、浏览器渲染机制

3、重排/回流、重绘

二、性能优化

1、性能优化原则

2、性能优化方法

3、首屏渲染优化

4、防抖和节流

三、安全

1、XSS跨站脚本攻击

2、CSRF/XSRF跨站请求伪造攻击

3、sql注入攻击

场景题


开发环境

 一、webpack、vite、babel

webpack、vite、babel

二、依赖管理

npm yarn 

三、git

常用命令

git add .

git branch

git checkout XX

git checkcout -b XX

git commit -m "XX"

git push origin master

git pull origin master

git merge XX

几个命令的区别

git fetch / git pull : pull = fetch + merge 

git reset / git revert:reset硬性回滚,回滚到过去某个点,目标版本后面的提交记录全部消失;revert 安全,添加新的提交来修复错误

git merge / git rebase:rebase提交记录是线性

四、Chrome调试工具

Elements Console debugger Network Application

五、抓包

移动端H5查看网络请求,需要用工具抓包。

Windows一般用fiddler,Mac OS一般用charles

六、linux常用命令

Linux

运行环境

一、网页加载过程

1、浏览器从输入URL到页面渲染的整个流程

1)加载资源(网络层面)

加载资源的形式:

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

加载资源的过程:

a)URL解析:浏览器解析输入的URL,确定协议、主机名、端口号和路径

b)DNS查询:浏览器会依据URL逐层查询DNS服务器缓存,解析URL中的域名对应的IP地址,DNS缓存从近到远依次是浏览器缓存、系统缓存、路由器缓存、IPS服务器缓存、域名服务器缓存、顶级域名服务器缓存。从哪个缓存找到对应的IP直接返回,不再查询后面的缓存。

c)TCP连接:结合三次握手

d)发送HTTP请求:浏览器发出读取文件的HTTP请求,该请求发送给服务器

e)服务器处理请求并返回HTTP报文:服务器对浏览器请求做出响应,把对应的带有HTML文本的HTTP响应报文发送给浏览器

f)浏览器解析渲染页面

g)连接结束:浏览器释放TCP连接,该步骤即四次挥手。第5步和第6步可以认为是同时发生的,哪一步在前没有特别的要求

2)页面渲染(渲染层面)

参见下面的浏览器渲染机制

参考:从输入URL到页面加载全过程、浏览器渲染从输入URL到页面加载的过程

 DNS域名解析流程

参考:面试宝典-DNS解析流程DNS域名解析过程

2、浏览器渲染机制

  1. 解析HTML生成DOM树
  2. 解析CSS生成CSSOM树(CSS规则树)
  3. 将DOM树与CSSOM树合并在一起生成Render Tree渲染树
  4.  布局。计算每个元素在视口中的确切位置和大小。首次布局称为"布局",后续布局称为"回流"或"重排"
  5. 绘制。将布局计算的几何信息转换为屏幕上的实际像素,包括文本、颜色、边框、阴影等视觉部分的绘制。通常分为多个层(layers)进行绘制
  6. 合成与显示。浏览器将各层合并(Composite)后显示在屏幕上,利用GPU加速处理某些层的合成

当HTML解析器遇到<script>标签时:

  • 暂停HTML文档解析
  • 下载并执行JavaScript代码(除非有async/defer属性)
  • 执行完成后继续解析HTML

window.onload和DOMContentLoaded区别

window.onload:页面的全部资源加载完才会执行,包括图片、视频等

DOMContentLoaded:DOM渲染完即可执行,此时图片、视频还可能没有加载完

参考:简述浏览器渲染机制、浏览器渲染

3、重排/回流、重绘

当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color,称为重绘(repaint)。

常见的引起重绘(repaint)属性和方法:

​​

当render tree中的一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建,称为回流(reflow)。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树。完成回流后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为重绘。

常见的引起回流(reflow)属性和方法:

​​

回流必将引起重绘,而重绘不一定会引起回流。比如:只有颜色改变的时候就只会发生重绘而不会引起回流

当页面布局和几何属性改变时就需要回流。比如:添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变

4、async和defer区别

在 HTML 中加载外部 JavaScript 脚本时,defer 和 async 是两个常用的脚本加载属性,它们都能实现脚本的异步加载

适用async的场景

<!-- 不依赖 DOM 的第三方库 -->
<script async src="https://cdn.example.com/library.js"></script>


const script = document.createElement('script');
script.src = 'script.js';
document.body.appendChild(script); // 动态加载脚本默认 async 行为

适用defer的场景

<!-- 主应用脚本(需要操作 DOM) -->
<script defer src="app.js"></script>

<!-- 依赖其他脚本的库 -->
<script defer src="library.js"></script>
<script defer src="dependent-script.js"></script> <!-- 保证在 library.js 后执行 -->


<script type="module" src="main.js"></script> // 模块化脚本默认具有 defer 行为(可以加上 async 改变行为)

参考:defer 和 async 的区别

二、性能优化

1、性能优化原则

多使用内存、缓存或其他方法

减少CPU计算量,减少网络加载耗时

(以空间换时间)

2、性能优化方法

1)加载更快

减少资源体积:压缩代码

减少访问次数:合并代码、SSR服务端渲染、缓存

使用更快的网络:CDN(根据区域做服务器处理)

2)渲染更快

CSS放在head,JS放在body最下面

尽早开始执行JS,用DOMContentLoaded触发

懒加载(图片懒加载,上滑加载更多)

对DOM查询进行缓存

频繁DOM操作,合并到一起插入DOM结构

节流throttle  防抖debounce

注:

SSR 服务器端渲染:将网页和数据一起加载,一起渲染

非SSR(前后端分离):先加载网页,再加载数据,再渲染数据

3、性能优化分类

1)首屏优化:见下

2)动画、动效优化:不掉帧

3)资源优化:去除lodash i18n 

...

指标支撑和怎么实现

4、首屏渲染优化

页面渲染性能指标

1) 关键渲染指标:

LCP最大内容绘制,测量加载性能,≤2.5秒

CLS累计布局偏移,测量视觉稳定性,≤0.1

2) 关键时间节点指标:

FP首次绘制 - 第一个像素出现

FCP首次内容绘制 - 第一个文本/图像内容出现

TTI可交互时间 - 页面完全可响应的时间

3)其他几个重要指标

TTFB 浏览器发送请求后接收到第一个字节的时间

INP 用户交互(点击、输入)到页面视觉反馈的时间

FP → FCP → LCP → DCL(DOM Content Loaded) → Load → TTI
           ↑
      布局稳定性(CLS)
首屏渲染优化核心手段

1)减少关键资源体积

  • 压缩HTML、CSS、JavaScript文件
  • 使用Tree-shaking移除未使用代码
  • 代码分割(Code Splitting)按需加载

2)优化关键渲染路径

  • 内联关键CSS(Critical CSS)
  • 延迟非关键CSS加载
  • 异步加载JavaScript(使用async/defer)

3)资源预加载

  • 使用<link rel="preload">预加载关键资源
  • DNS预解析<link rel="dns-prefetch">
  • 预连接<link rel="preconnect">

参考:前端性能优化 - 首屏渲染优化实现及其必要性

5、防抖和节流

防抖:用户动作暂停或结束,触发请求。

  • 持续触发不执行
  • 不触发的一段时间之后再执行

应用场景:

  • search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
  • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
HTML:
    <input id="input1">
    <script src="js/debounce.js"></script>

js:
const input1=document.getElementById('input1')

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))

节流 

  • 持续触发并不会执行多次
  • 到一定时间再去执行

应用场景:

  • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
  • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
HTML:
<div id="div1" draggable="true">可拖拽</div>
<script src="js/throttle.js"></script>
CSS:
#div1{
    border:1px solid #ccc;
    width:200px;
    height:200px;
}

js:
const div1=document.getElementById('div1')

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)
},200))

参考:函数的防抖和节流是个啥浅谈 JS 防抖和节流

手写防抖/节流

// 防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次触发,则重新计算时间
function debounce(func, time) {
    let timeout=null;
    return function () {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            func.apply(this, arguments)
        }, time);
    }
}

// 节流:高频事件触发,n秒内只会执行一次
// 时间戳版本
function throttle(func, delay) {
  let lastTime = 0;
  
  return function(...args) {
    const now = Date.now();
    
    // 如果距离上次执行时间大于delay则执行
    if (now - lastTime >= delay) {
      func.apply(this, args);
      lastTime = now;
    }
  };
}
// 定时器版本
function throttle(func, delay) {
  let timer = null;
  
  return function(...args) {
    if (!timer) {
      timer = setTimeout(() => {
        func.apply(this, args);
        timer = null;
      }, delay);
    }
  };
}

三、安全

常见的web前端攻击方式

1、XSS跨站脚本攻击

攻击者在web页面插入恶意的代码。当用户浏览该页面的时候,代码执行,从而实现攻击目的。

防御:

输入过滤,对用户提交的数据进行有效性验证,仅接受指定长度范围内并符合我们期望格式的的内容提交,阻止或者忽略除此外的其他任何数据。

输出编码,把变量输出到页面时要做好相关的编码转义工作,如要输出到 <script>中,可以进行JS编码;要输出到HTML内容或属性,则进行HTML编码处理。根据不同的语境采用不同的编码处理方式。

限制可执行脚本的来源。

HttpOnly Cookie,将重要的cookie标记为http only, 这样的话当浏览器向Web服务器发起请求时就会带上cookie字段,但是在脚本中却不能访问这个cookie,这样就避免了XSS攻击利用JavaScript的document.cookie获取cookie

2、CSRF/XSRF跨站请求伪造攻击

攻击者诱导用户访问恶意网站,该网站自动向目标网站发起请求(利用用户已登录状态)

防御:

使用CSRF Token:服务器生成随机token,表单提交时验证

SameSite Cookie属性:设置Cookie的SameSite属性为Strict或Lax(默认)

验证Referer/Origin头部:检查请求来源是否合法

关键操作二次验证:如短信/邮箱验证码、密码确认

避免使用GET进行状态修改:遵循REST规范

参考:XSS跨站脚本攻击与CSRF跨站请求伪造攻击的学习总结

3、sql注入攻击

SQL注入是一种通过操作输入来修改后台SQL语句进行攻击的技术。

防御:

使用参数化查询(Prepared Statements):避免SQL拼接

最小权限原则:数据库账户使用最低必要权限

输入验证:严格限制输入数据的类型和格式

场景题

项目:工程化;性能优化;稳定性、用户体验

场景题思路:交代背景、调研方案、方案落地、反思追求更优解

1、Promise相关,如何解决页面请求接口大规模并发?

实现一个带并发限制的一步调度器 Scheduler,保证同时运行的任务最多有N个

// 实现一个带并发限制的一步调度器 Scheduler,保证同时运行的任务最多有N个。完善下面代码中的Schedule类,使得以下程序能够正确输出
class Scheduler {
  add(promiseCreator){

  }
}

const timeout = (time) => new Promise(resolve => {
  setTimeout(resolve, time)
})

const scheduler = new Scheduler(n)
const addTask = (time, order) => {
  scheduler.add(() => timeout(time)).then(() => console.log(order))
}


addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')

// 打印顺序:2 3 1 4
class Scheduler {
  constructor(max) {
    this.max = max;
    this.count = 0; // 用来记录当前正在执行的异步函数
    this.queue = new Array(); // 等待队列
  }

  async add(promiseCreator) {
    if(this.count >= this.max) {
      await new Promise((resolve, reject) => this.queue.push(resolve));
    }

    this.count++;
    let res = await promiseCreator();
    this.count--;
    if(this.queue.length){
      this.queue.shift();
    }
    return res;
  }
}

const timeout = time => new Promise(resolve => {
  setTimeout(resolve, time);
});
const scheduler = new Scheduler(2);
const addTask = (time, order) => {
  scheduler.add(() => timeout(time)).then(() => console.log(order))
}

addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')

页面请求接口大规模并发?100个请求,如何使用promise控制并发?

根本解法:滑动窗口算法

请求队列、防抖节流、分页滚动加载

// 请求队列
class RequestQueue {
    constructor(maxConcurrent) {
        this.maxConcurrent = maxConcurrent; // 最大并发请求数
        this.currentConcurrent = 0; // 当前并发请求数
        this.queue = []; // 请求队列
    }

    add(request) {
        return new Promise((resolve, reject) => {
            this.queue.push({request, resolve, reject});
            this.processQueue();
        })
    }

    processQueue(){
        if(this.queue.length > 0 && this.currentConcurrent < this.maxConcurrent) {
            const {request, resolve, reject}=this.queue.shift();
            this.currentConcurrent++;
            request()
                .then(resolve)
                .catch(reject)
                .finally(()=>{
                    this.currentConcurrent--;
                    this.processQueue();
                });
        }
    }
}


// 请求示例
function fetchData(url){
    return fetch(url).then(response => response.json());
}

// 使用请求队列
const requestQueue = new RequestQueue(5);
const urls=[
    "",
    ""
]
const requests = urls.map(url => fetchData(url));

Promise.all(requests.map(request => requestQueue.add(request)))
        .then(result => {
            console.log('请求完成',result);
        }).catch(error => {
            console.log('请求失败',error);
        })
// 分页加载
let currentPage = 1;
const pageSize = 20;
let isLoading = false;

function loadMoreData(){
    if(isLoading) return;
    isLoading=true;

    fetch('/api/item?page=${currentPage}&size=${pageSize}')
    .then(response => reponse.json())
    .then(data => {
        const container = document.getElementById('item-container')
        data.items.forEach(item => {
            const dv=document.creatElement('div);
            dv.textContext = item.name;
            container.appendChild(dv);
        })
        currentPage++;
        isLoading=false;
    }).catch(error=>{
        console.log('请求失败',error);
        isLoading=false;
    })
}

window.addEventListener('scroll',()=>{
    if(window.innerHeight + window.scrollY >= document.body.offset) {
        loadMoreData();
    }
})

// 初始加载
loadMoreData();

2、hook

实现useLatest(获取传入参数最新变化结果)、

usePrevious(获取上次变化结果)、

useCountDown(倒计时)...

import { useRef } from 'react'

const useLatest = (value) => {
    const ref = uewRef(value);
    ref.current = value;
    return ref;
}

const usePrevious = (value) => {
    const ref = uewRef(value);

    useEffect(()=>{
        ref.current = value
    },[value])

    return ref.current;
}

hook分类:

1)dom相关的,点击事件、双击、长按

2)effect

3)common,请求的处理、方法的调用

3、出现白屏怎么排查原因?

1)控制台检查

打开浏览器开发者工具(F12),查看Console面板是否有报错(红色错误),注意警告(黄色提示)也可能导致问题

2)网络请求分析

切换到Network面板,检查关键资源(HTML、JS、CSS)是否加载成功,查看失败的请求(状态码4xx/5xx)

3)DOM结构验证

在Elements面板检查DOM是否正常渲染,查看<body>内是否有内容

4、前端埋点SDK设计思路?

数据流设计:采集 -> 处理 -> 缓存 -> 上报

采集:支持自动采集和手动采集,核心用户行为包括页面浏览、元素点击、元素曝光、错误事件、接口请求、自定义事件

处理:统一数据格式、数据清洗、加密处理

存储:本地临时缓存待上报数据

上报:上报策略包括批量上报、定时上报、即时上报、页面离开上报,重试机制

设计原则:

1)无侵入性

对业务代码影响最小化;自动收集通用数据(页面访问、性能指标等)

2)高性能

异步上报机制;数据批量压缩上传;不影响主线程性能

3)可扩展性

支持多种埋点类型;插件化架构设计;自定义上报策略

5、全站请求耗时统计工具设计思路

通过该工具可以更清晰的看到整个站点的性能情况,比如首屏加载时间等

1)监控请求耗时,HTTP中间件,axios请求发起和返回时间

2)前端监控

3)后端监控

4)数据汇总:数据清洗和加工,数据可视化

6、前端页面截图

canvas(canvas原生API、第三方库html2canvas)、puppeteer(无头浏览器),上传CDN

全页面截图、局部截图,(selector选body就是全页面,选dom节点作为局部区域的节点)

7、前端水印

为了保证用户隐私(文档保护、图片保护、视频保护)、数据相对安全,需要实现水印waterMark

肉眼可见的水印:明水印;不可见的:暗水印

实现明水印的方式:

1)背景图background-image: url(带水印的图片)或者css伪元素;

2)DOM元素平铺实现,创建多个 DOM 元素作为水印单元,手动控制排列和密度,适合复杂样式或交互需求

3)Canvas(性能好),Canvas绘制水印图案,转为图片后作为背景图重复平铺,支持动态文字

注意事项:

1)层级控制,水印z-index需小于内容区域

2)防篡改,MutationObserver监听DOM元素变化,当检测到水印元素被删除时,重新生成水印

实现暗水印的方式:

将信息写入到文件二进制代码里,后端实现

8、图片性能优化(图片懒加载)方案

1)loading="lazy",浏览器原生懒加载,缺点:不支持背景图、视频等资源,兼容性有限

<img src="" alt="XX" loading="lazy"/>

2)Intersection observer API、监听滚动事件,判断元素是否进入视口,再动态加载资源(最原始的方法,一般不用)

4)使用三方库lazysizes

9、大文件上传

前端切片 chunk,例1024M,切片大小500K,size=1024*1024/500;

将切片传递给后端,切片取名hash-index;

后端组合切片

优化:前端切片主进程卡顿,webworker多进程切片,处理完交给主线程发送;

切完后,将blob存储到IndexDB,下次用户进来之后,嗅探一下是否存在未完成上传的切片,有就尝试继续上传;

websocket,实时通知和请求队列的控制;

10、如何修改第三方npm包

稳定库,node_modules直接改、patch方案、fork package自己维护

// 简单修改,patch方案
npm install patch-package postinstall

{
    "scripts": {"postinstall": "patch-package"} 
}

创建补丁,如npx patch-package rspack,会在根目录下生成一个文件夹patches/rspack+1.0.0.patch
// 长久方案,fork
直接改源码,源码改完构建发布到npm私服

11、上拉加载、下拉刷新怎么实现?

一般用于长列表,上拉加载、下拉刷新提升性能

上拉加载实现步骤

滚动事件监听、

怎么判断触底、

回调触发列表加载更多

// 上拉加载
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
</head>
<body>
    <div id="list"></div>
    <script>
        const list = document.getElementById('list');
        let page = 1;

        function loadMoreData(page){
            return fetch(`http://example.com/api/data?page=${page}`)
                .then(response => response.json())
                .then(data => {
                    data.items.forEach(item => {
                        const div = document.createElement('div');
                        div.className = 'item';
                        div.textContent = item.text;
                        lsit.appendChild(div);
                    })
                })
        }

        function handleScroll(){
            if(list.scrollTop + list.clientHeight >= list.scrollHeight-10){
                page++;
                loadMoreData(page);
            }
        }

        list.addEventListener('scroll', handleScroll);

        // 初始load
        loadMoreData(page);
    </script>
</body>
</html>

下拉刷新实现步骤

触摸事件监听(touchstart、touchmove、touchend)、

显示刷新的指示器,显示有没有达到下拉阈值、

触发刷新操作

// 下拉刷新
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
</head>
<body>
    <div id="list">
        <div id="refreshIndicator">Refreshing...</div>
    </div>
    <script>
        const list = document.getElementById('list');
        const refreshIndicator = document.getElementById('refreshIndicator');
        let startY = 0;
        let isPulling = false;

        function loadData(){
            return fetch('http://example.com/api/data')
                .then(response => response.json())
                .then(data => {
                    list.innerHtml = ''; // 清空现有数据
                    data.items.forEach(item => {
                        const div = document.createElement('div');
                        div.className = 'item';
                        div.textContent = item.text;
                        lsit.appendChild(div);
                    })
                    refreshIndicator.style.display = 'none';
                })
        }

        list.addEventListener('touchstart', (event)=>{
            if(list.scrollTop === 0){
                startY = evnet.touches[0].pageY;
                isPulling = true;
            }
        });

        list.addEventListener('touchmove', (event)=>{
            if(isPulling){
                const currentY = event.touches[0].pageY;
                if(currentY>startY){
                    refreshIndicator.style.display='block';
                    refreshIndicator.style.height=`${currentY-startY}px`
                }
            }
        })

        list.addEventListener('touchend', ()=>{
            if(isPulling){
                const refreshHeight = parseInt(refreshIndicator.style.height, 10);
                if(refreshHeight > 50){
                    loadData();
                }else{
                    refreshIndicator.style.display='none';
                }
                isPulling=false;
                refreshIndicator.style.height='50px';
            }
        })

        // 初始load
        loadData();
    </script>
</body>
</html>

性能优化、用户体验、兼容

1)性能优化:防抖节流、懒加载

2)用户体验:视觉反馈,下拉显示器、平滑动画、异常处理

3)兼容:触摸事件兼容

12、网页加载过程中的进度条怎么实现?

1)监听事件

// 页面加载时的伪进度条
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #progress-bar {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 4px;
            background-color: #29d;
            z-index: 9999;
            transition: width 0.4s ease;
        }
    </style>
</head>
<body>
    <div id="progress-bar"></div>
    <script>
        function simulateLoadingProgress() {
            const progressBar = document.getElementById('progress-bar');
            let width = 0;
            const interval = setInterval(()=>{
                if(width>=100){
                    clearInterval(interval);
                    progressBar.style.width='100%';
                    setTimeout(()=>{
                        progressBar.style.display='none';
                    },500)
                }else{
                    width+=10;
                    progressBar.style.width=width+'%';
                }
            },200)
        }

        window.addEventListener('load', () => {
            simulateLoadingProgress();
        })
    </script>
</body>
</html>
// 请求实现 怎么拿到进度(fetch、ajax)、怎么绘制(svg、dom)
<body>
    <div id="progress-bar"></div>
    <script>
        function loadResource(url) {
            const xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.onpregress = function(event) {
                if(event.lengthComputable) {
                    const percentComplete = (event.loaded/event.total) * 100;
                    document.getElementById('progress-bar').style.width=percentComplete+'%';
                }
            }
            xhr.onload = function(){
                if(xhr.status === 200){
                    document.getElementById('progress-bar').style.width = '100%';
                    setTimeout(()=>{
                        document.getElementById('progress-bar').style.display = 'none';
                    },500)
                }
            }
            xhr.send();
        }

        window.addEventListener('load', () => {
            loadResource('http://example.com/file')
        })
    </script>
</body>

2)react框架 nprogress

13、超过Number最大值的数怎么处理?

bigInt、三方库如decimal.js或big.js、格式化成带单位的数字、用户输入场景限制输入大小

14、静态资源加载失败的场景降级处理

场景:图片、css文件、js文件、CDN、字体文件、服务端渲染失败

1)图片:占位图、alt描述图片、重试机制(404、无权限)、上报服务器

2)css:关键样式通过内联、备用样式、上报

3)js:内联脚本、备用脚本、上报

4)CDN:本地备份、动态切换,切换到另一个有用的CDN服务

5)字体:使用降级字体(apple 微软雅黑)、webfont处理字体

6)SSR:降级的html用于渲染

补:常见 WebFont 格式:woff/woff2、ttf、eot、svg

使用方法:1)引入字体文件 2)使用在线字体服务

// 定义字体
@font-face {
    font-family: "MyFont"; // 字体名称自定义
    src: url("myfont.woff2") format("woff2")
         url("myfont.woff") format("woff")
    font-weight: 400; // 字体粗细(正常)
    font-style: normal; // 字体样式(正常)
}

// 使用字体
body {
    font-family: "MyFont", sans-serif; // 备选字体(无自定义字体时 fallback)
}
<!-- 引入 Google Fonts 的 Roboto 字体 -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">

<style>
  body {
    font-family: 'Roboto', sans-serif;
  }
</style>

15、window上频繁绑定内容,有什么风险?

1)命名冲突

2)全局污染

3)安全风险

4)性能问题,增加内存开销(只绑定没有卸载)

解决方案:1)模块化 2)命名空间 3)IIFE(形成闭包) 4)开启严格模式

16、QPS达到峰值时该如何处理?(偏全栈)

请求限流:

// node.js
const rateLimit = require('express-rate-limit')

const limiter = rateLimit({
    windowMs: 60*1000,
    max: 100,
    message: '太多了等等',
})

请求合并:debounce、throttle

请求缓存:react库SWR,针对请求的内容缓存。请求参数、请求方法、请求逻辑依赖的内容没有变化,直接命中缓存

任务队列

17、DNS协议的理解(计算机网络)

将域名映射到IP上,例如www.baidu.com -> 127.0.0.1

用户输入域名,检查自身DNS缓存、操作系统DNS缓存、本地域名服务器、根据本地DNS服务器去查找根域名服务器、顶级域名服务器直到获取到IP为止,返回结果后浏览器缓存并向IP发送请求

DNS记录类型:

1)A记录,将域名映射到IPv4地址

2)4A记录,将域名映射到IPv6地址

3)CNAME记录(中介),将一个域名映射到另一个域名

4)MX记录(不常用),指定邮件服务器

5)TXT,文本信息存储,一般做域名验证或SPF验证

DNS常见问题:

1)DNS解析慢:

  • DNS预解析
  • 使用CDN
  • 减少外部的资源请求,自己的域名+OSS+外部CDN地址

2)DNS劫持:

  • HTTPS协议,证书保证传输的安全性
  • DNSSEC,DNS安全扩展

优化:

DNS缓存、工具nslookup和dig、在线工具dns.google.com

18、深度SEO优化细节(服务端渲染相关公司)

SEO搜索引擎优化,实现方案:

1)页面结构优化,语义化标签

2)内容优化,保证页面中关键词的覆盖率

3)技术向SEO优化,站点地图robots.txt、结构化数据、移动端兼容处理(响应式处理)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值