文章目录前言一、同源策略与跨域1.1 同源定义1.2 跨域解决方案二、跨标签页通信2.1 BroadcastChannel2.2 localStorage 事件2.3 SharedWorker2.4 方案对比三、SSE vs WebSocket3.1 SSEServer-Sent Events3.2 WebSocket3.3 区别四、离线存储方案选型4.1 方案对比4.2 选型指南五、「从输入 URL 到页面显示」5.1 完整流程5.2 面试回答要点六、高频手写题汇总6.1 防抖6.2 节流6.3 深拷贝6.4 Promise.all6.5 发布订阅七、易混淆点八、思考与练习总结前言本篇是系列文章的收尾汇总面试高频手写题和综合性问题帮助系统性复习。内容涵盖同源策略与跨域跨标签页通信SSE vs WebSocket离线存储方案选型「从输入 URL 到页面显示」串联题一、同源策略与跨域1.1 同源定义// 同源协议、域名、端口完全相同https://example.com:443/path ↓ ↓ ↓ 协议 域名 端口// 不同源的情况// 协议不同http vs https// 域名不同example.com vs api.example.com// 端口不同:80 vs :80801.2 跨域解决方案// 1. CORS最常用// 服务端设置响应头Access-Control-Allow-Origin:https://example.com Access-Control-Allow-Methods:GET,POST,PUT,DELETEAccess-Control-Allow-Headers:Content-Type,Authorization Access-Control-Allow-Credentials:true// 允许携带 Cookie// 2. 代理// 开发环境devServer proxydevServer:{proxy:{/api:http://localhost:8080}}// 生产环境Nginx 反向代理location/api{proxy_pass http://backend:8080;}// 3. JSONP只支持 GETfunctionjsonp(url,callback){constscriptdocument.createElement(script)script.src${url}?callback${callback}document.body.appendChild(script)}// 4. postMessage跨窗口通信otherWindow.postMessage(data,targetOrigin)二、跨标签页通信2.1 BroadcastChannel// 标签页 AconstchannelnewBroadcastChannel(my-channel)channel.postMessage({type:update,data:Hello})// 标签页 BconstchannelnewBroadcastChannel(my-channel)channel.onmessage(event){console.log(event.data)// { type: update, data: Hello }}2.2 localStorage 事件// 标签页 AlocalStorage.setItem(message,JSON.stringify({text:Hello}))// 标签页 Bwindow.addEventListener(storage,(event){if(event.keymessage){console.log(JSON.parse(event.newValue))}})2.3 SharedWorker// worker.jsconstports[]onconnect(e){constporte.ports[0]ports.push(port)port.onmessage(event){// 广播给其他标签页ports.forEach(p{if(p!port)p.postMessage(event.data)})}}// 标签页constworkernewSharedWorker(worker.js)worker.port.onmessage(e)console.log(e.data)worker.port.postMessage(Hello from tab A)2.4 方案对比方案适用场景兼容性BroadcastChannel同源标签页通信现代浏览器localStorage简单数据同步全兼容SharedWorker复杂逻辑共享现代浏览器postMessage跨域窗口通信全兼容三、SSE vs WebSocket3.1 SSEServer-Sent Events// 客户端constsourcenewEventSource(/api/events)source.onmessage(event){console.log(event.data)}source.addEventListener(custom,(event){console.log(event.data)})source.onerror(event){console.log(连接错误)}// 服务端Node.jsapp.get(/api/events,(req,res){res.setHeader(Content-Type,text/event-stream)res.setHeader(Cache-Control,no-cache)res.setHeader(Connection,keep-alive)setInterval((){res.write(data:${JSON.stringify({time:Date.now()})}\n\n)},1000)})3.2 WebSocket// 客户端constwsnewWebSocket(ws://localhost:8080)ws.onopen(){ws.send(Hello Server)}ws.onmessage(event){console.log(event.data)}ws.onclose(){console.log(连接关闭)}// 服务端Node.js wsconstWebSocketrequire(ws)constwssnewWebSocket.Server({port:8080})wss.on(connection,(ws){ws.on(message,(message){ws.send(Echo:${message})})})3.3 区别对比项SSEWebSocket方向服务端 → 客户端单向双向通信协议HTTP独立协议ws://数据格式文本文本 二进制自动重连支持需手动实现适用场景通知、实时数据推送聊天、游戏、协作编辑四、离线存储方案选型4.1 方案对比方案容量过期机制适用场景Cookie4KB设置过期时间认证状态、会话管理localStorage5-10MB永久需手动清除用户偏好、缓存数据sessionStorage5-10MB会话结束表单暂存、页面状态IndexedDB无限制无大量结构化数据、离线应用Cache API无限制手动管理资源缓存、Service Worker4.2 选型指南// 1. 小量简单数据 → Cookiedocument.cookiesessionabc; max-age3600; secure; httponly// 2. 中量键值对 → localStoragelocalStorage.setItem(theme,dark)localStorage.setItem(lang,zh-CN)// 3. 会话级数据 → sessionStoragesessionStorage.setItem(formData,JSON.stringify(formData))// 4. 大量结构化数据 → IndexedDBconstrequestindexedDB.open(myDB,1)request.onupgradeneeded(event){constdbevent.target.result db.createObjectStore(users,{keyPath:id})}// 5. 资源缓存 → Cache API Service Workercaches.open(v1).then(cache{cache.addAll([/index.html,/styles.css,/app.js])})五、「从输入 URL 到页面显示」5.1 完整流程1. URL 解析 - 浏览器解析 URL协议、域名、端口、路径、参数 2. DNS 解析 - 浏览器缓存 → 系统缓存 → 路由器 → ISP → 根域名服务器 - 递归查询获取 IP 地址 3. 建立 TCP 连接 - 三次握手SYN → SYNACK → ACK - HTTPS 还需要 TLS 握手 4. 发送 HTTP 请求 - 请求行方法、路径、协议版本 - 请求头Host、Cookie、Content-Type 等 - 请求体POST 数据 5. 服务器处理 - 负载均衡 → Web 服务器 → 应用服务器 → 数据库 - 返回 HTTP 响应 6. 浏览器渲染 - 解析 HTML → 构建 DOM 树 - 解析 CSS → 构建 CSSOM 树 - 合并 DOM CSSOM → 渲染树 - 布局Layout→ 绘制Paint→ 合成Composite 7. JavaScript 执行 - 下载、解析、执行 JS - 可能修改 DOM/CSSOM触发重排/重绘5.2 面试回答要点// 回答结构// 1. 网络阶段// - DNS 解析迭代/递归查询// - TCP 三次握手// - TLS 握手HTTPS// - HTTP 请求/响应// 2. 解析阶段// - HTML 解析 → DOM 树// - CSS 解析 → CSSOM 树// - 合并 → 渲染树// 3. 渲染阶段// - 布局计算位置大小// - 绘制生成像素// - 合成GPU 合成图层// 4. 优化点// - DNS 预解析link reldns-prefetch// - 预连接link relpreconnect// - 资源提示preload、prefetch// - 关键渲染路径优化六、高频手写题汇总6.1 防抖functiondebounce(fn,delay){lettimernullreturnfunction(...args){clearTimeout(timer)timersetTimeout(()fn.apply(this,args),delay)}}6.2 节流functionthrottle(fn,interval){letlastTime0returnfunction(...args){constnowDate.now()if(now-lastTimeinterval){lastTimenowfn.apply(this,args)}}}6.3 深拷贝functiondeepClone(obj,mapnewWeakMap()){if(objnull||typeofobj!object)returnobjif(map.has(obj))returnmap.get(obj)constresultArray.isArray(obj)?[]:{}map.set(obj,result)for(constkeyofReflect.ownKeys(obj)){result[key]deepClone(obj[key],map)}returnresult}6.4 Promise.allfunctionpromiseAll(promises){returnnewPromise((resolve,reject){constresults[]letcount0promises.forEach((promise,index){Promise.resolve(promise).then((value){results[index]valueif(countpromises.length)resolve(results)},reject)})if(promises.length0)resolve(results)})}6.5 发布订阅classEventEmitter{events{}on(event,callback){if(!this.events[event])this.events[event][]this.events[event].push(callback)return()this.off(event,callback)}off(event,callback){if(!this.events[event])returnthis.events[event]this.events[event].filter(cbcb!callback)}emit(event,...args){if(!this.events[event])returnthis.events[event].forEach(cbcb(...args))}}七、易混淆点同源策略限制限制 AJAX 跨域请求但不限制script、img、link等标签的跨域加载。SSE vs WebSocketSSE 是单向服务端 → 客户端WebSocket 是双向。SSE 基于 HTTPWebSocket 是独立协议。localStorage vs sessionStoragelocalStorage 永久存储需手动清除sessionStorage 会话结束自动清除。Cookie vs TokenCookie 自动携带Token 需手动设置请求头。Cookie 有大小限制Token 无限制。八、思考与练习1.同源策略限制了什么不限制什么解析限制AJAX 跨域请求、Cookie 读取、DOM 访问不限制script、img、link、video等标签的跨域加载2.跨标签页通信有哪些方案解析BroadcastChannel同源标签页专用localStorage storage 事件简单数据同步SharedWorker复杂逻辑共享postMessage跨域窗口通信3.从输入 URL 到页面显示经历了哪些步骤解析URL 解析DNS 解析TCP 三次握手HTTPS 还需 TLS 握手HTTP 请求/响应HTML 解析 → DOM 树CSS 解析 → CSSOM 树合并 → 渲染树布局 → 绘制 → 合成4.localStorage 和 sessionStorage 的区别解析localStorage永久存储需手动清除同源所有标签页共享sessionStorage会话级存储标签页关闭自动清除仅当前标签页可用5.SSE 和 WebSocket 的区别解析SSE单向服务端 → 客户端基于 HTTP自动重连适用于通知、实时数据推送WebSocket双向通信独立协议需手动重连适用于聊天、游戏、协作编辑总结同源策略协议、域名、端口相同限制 AJAX 跨域跨域方案CORS最常用、代理、JSONP、postMessage跨标签通信BroadcastChannel、localStorage、SharedWorker、postMessageSSE vs WebSocket前者单向基于 HTTP后者双向独立协议离线存储Cookie4KB、localStorage/sessionStorage5-10MB、IndexedDB无限制URL 到页面DNS → TCP → HTTP → 解析 → 渲染