news 2026/6/13 11:22:58

前端综合实战:跨域通信、离线存储与 URL 到页面全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端综合实战:跨域通信、离线存储与 URL 到页面全流程

文章目录

  • 前言
  • 一、同源策略与跨域
    • 1.1 同源定义
    • 1.2 跨域解决方案
  • 二、跨标签页通信
    • 2.1 BroadcastChannel
    • 2.2 localStorage 事件
    • 2.3 SharedWorker
    • 2.4 方案对比
  • 三、SSE vs WebSocket
    • 3.1 SSE(Server-Sent Events)
    • 3.2 WebSocket
    • 3.3 区别
  • 四、离线存储方案选型
    • 4.1 方案对比
    • 4.2 选型指南
  • 五、「从输入 URL 到页面显示」
    • 5.1 完整流程
    • 5.2 面试回答要点
  • 六、高频手写题汇总
    • 6.1 防抖
    • 6.2 节流
    • 6.3 深拷贝
    • 6.4 Promise.all
    • 6.5 发布订阅
  • 七、易混淆点
  • 八、思考与练习
  • 总结

前言

本篇是系列文章的收尾,汇总面试高频手写题和综合性问题,帮助系统性复习。内容涵盖:

  • 同源策略与跨域
  • 跨标签页通信
  • SSE vs WebSocket
  • 离线存储方案选型
  • 「从输入 URL 到页面显示」串联题

一、同源策略与跨域

1.1 同源定义

// 同源:协议、域名、端口完全相同https://example.com:443/path ↓ ↓ ↓ 协议 域名 端口// 不同源的情况:// 协议不同:http vs https// 域名不同:example.com vs api.example.com// 端口不同::80 vs :8080

1.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(只支持 GET)functionjsonp(url,callback){constscript=document.createElement('script')script.src=`${url}?callback=${callback}`document.body.appendChild(script)}// 4. postMessage(跨窗口通信)otherWindow.postMessage(data,targetOrigin)

二、跨标签页通信

2.1 BroadcastChannel

// 标签页 Aconstchannel=newBroadcastChannel('my-channel')channel.postMessage({type:'update',data:'Hello'})// 标签页 Bconstchannel=newBroadcastChannel('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.key==='message'){console.log(JSON.parse(event.newValue))}})

2.3 SharedWorker

// worker.jsconstports=[]onconnect=(e)=>{constport=e.ports[0]ports.push(port)port.onmessage=(event)=>{// 广播给其他标签页ports.forEach(p=>{if(p!==port)p.postMessage(event.data)})}}// 标签页constworker=newSharedWorker('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 WebSocket

3.1 SSE(Server-Sent Events)

// 客户端constsource=newEventSource('/api/events')source.onmessage=(event)=>{console.log(event.data)}source.addEventListener('custom',(event)=>{console.log(event.data)})source.onerror=(event)=>{console.log('连接错误')}// 服务端(Node.js)app.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

// 客户端constws=newWebSocket('ws://localhost:8080')ws.onopen=()=>{ws.send('Hello Server')}ws.onmessage=(event)=>{console.log(event.data)}ws.onclose=()=>{console.log('连接关闭')}// 服务端(Node.js + ws)constWebSocket=require('ws')constwss=newWebSocket.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 Worker

4.2 选型指南

// 1. 小量简单数据 → Cookiedocument.cookie='session=abc; max-age=3600; secure; httponly'// 2. 中量键值对 → localStoragelocalStorage.setItem('theme','dark')localStorage.setItem('lang','zh-CN')// 3. 会话级数据 → sessionStoragesessionStorage.setItem('formData',JSON.stringify(formData))// 4. 大量结构化数据 → IndexedDBconstrequest=indexedDB.open('myDB',1)request.onupgradeneeded=(event)=>{constdb=event.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 → SYN+ACK → 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 rel="dns-prefetch">// - 预连接:<link rel="preconnect">// - 资源提示:preload、prefetch// - 关键渲染路径优化

六、高频手写题汇总

6.1 防抖

functiondebounce(fn,delay){lettimer=nullreturnfunction(...args){clearTimeout(timer)timer=setTimeout(()=>fn.apply(this,args),delay)}}

6.2 节流

functionthrottle(fn,interval){letlastTime=0returnfunction(...args){constnow=Date.now()if(now-lastTime>=interval){lastTime=nowfn.apply(this,args)}}}

6.3 深拷贝

functiondeepClone(obj,map=newWeakMap()){if(obj===null||typeofobj!=='object')returnobjif(map.has(obj))returnmap.get(obj)constresult=Array.isArray(obj)?[]:{}map.set(obj,result)for(constkeyofReflect.ownKeys(obj)){result[key]=deepClone(obj[key],map)}returnresult}

6.4 Promise.all

functionpromiseAll(promises){returnnewPromise((resolve,reject)=>{constresults=[]letcount=0promises.forEach((promise,index)=>{Promise.resolve(promise).then((value)=>{results[index]=valueif(++count===promises.length)resolve(results)},reject)})if(promises.length===0)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(cb=>cb!==callback)}emit(event,...args){if(!this.events[event])returnthis.events[event].forEach(cb=>cb(...args))}}

七、易混淆点

  1. 同源策略限制:限制 AJAX 跨域请求,但不限制<script><img><link>等标签的跨域加载。
  2. SSE vs WebSocket:SSE 是单向(服务端 → 客户端),WebSocket 是双向。SSE 基于 HTTP,WebSocket 是独立协议。
  3. localStorage vs sessionStorage:localStorage 永久存储(需手动清除),sessionStorage 会话结束自动清除。
  4. Cookie vs Token:Cookie 自动携带,Token 需手动设置请求头。Cookie 有大小限制,Token 无限制。

八、思考与练习

1.同源策略限制了什么?不限制什么?

解析:

  • 限制:AJAX 跨域请求、Cookie 读取、DOM 访问
  • 不限制<script><img><link><video>等标签的跨域加载

2.跨标签页通信有哪些方案?

解析:

  • BroadcastChannel:同源标签页专用
  • localStorage + storage 事件:简单数据同步
  • SharedWorker:复杂逻辑共享
  • postMessage:跨域窗口通信

3.从输入 URL 到页面显示经历了哪些步骤?

解析:

  1. URL 解析
  2. DNS 解析
  3. TCP 三次握手(HTTPS 还需 TLS 握手)
  4. HTTP 请求/响应
  5. HTML 解析 → DOM 树
  6. CSS 解析 → CSSOM 树
  7. 合并 → 渲染树
  8. 布局 → 绘制 → 合成

4.localStorage 和 sessionStorage 的区别?

解析:

  • localStorage:永久存储,需手动清除,同源所有标签页共享
  • sessionStorage:会话级存储,标签页关闭自动清除,仅当前标签页可用

5.SSE 和 WebSocket 的区别?

解析:

  • SSE:单向(服务端 → 客户端),基于 HTTP,自动重连,适用于通知、实时数据推送
  • WebSocket:双向通信,独立协议,需手动重连,适用于聊天、游戏、协作编辑

总结

  • 同源策略:协议、域名、端口相同,限制 AJAX 跨域
  • 跨域方案:CORS(最常用)、代理、JSONP、postMessage
  • 跨标签通信:BroadcastChannel、localStorage、SharedWorker、postMessage
  • SSE vs WebSocket:前者单向基于 HTTP,后者双向独立协议
  • 离线存储:Cookie(4KB)、localStorage/sessionStorage(5-10MB)、IndexedDB(无限制)
  • URL 到页面:DNS → TCP → HTTP → 解析 → 渲染
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 11:15:08

Mythos推理架构:可编程、可审计的门控式高阶推理系统

1. 项目概述&#xff1a;一次被刻意“锁住”的能力跃迁如果你最近关注大模型前沿动态&#xff0c;大概率在技术社区、AI从业者群或邮件列表里见过“TAI #200”这个编号——它不是某篇论文的DOI&#xff0c;也不是某个开源项目的Release Tag&#xff0c;而是The AI Alignment Ne…

作者头像 李华
网站建设 2026/6/13 11:11:23

如何高效实现番茄小说离线阅读:专业工具完整指南

如何高效实现番茄小说离线阅读&#xff1a;专业工具完整指南 【免费下载链接】Tomato-Novel-Downloader 番茄小说下载器不精简版 项目地址: https://gitcode.com/gh_mirrors/to/Tomato-Novel-Downloader 在数字阅读日益普及的今天&#xff0c;番茄小说下载器为读者提供了…

作者头像 李华
网站建设 2026/6/13 11:09:55

OpCore-Simplify:终极Hackintosh配置简化引擎实战指南

OpCore-Simplify&#xff1a;终极Hackintosh配置简化引擎实战指南 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify OpCore-Simplify是一款革命性的Open…

作者头像 李华
网站建设 2026/6/13 11:09:03

工具调用协议:模型如何决定调用哪个工具

Agent 会做事&#xff0c;不是因为模型“有手”。 它能做事&#xff0c;是因为 OpenClaw 把工具能力以 schema 和协议的形式交给模型&#xff0c;再把模型的工具调用请求送到真实执行层。 先说结论&#xff1a;工具调用是一次协议协作 一次工具调用大致是&#xff1a; Open…

作者头像 李华
网站建设 2026/6/13 11:00:22

跨平台USB设备共享神器:USB/IP Windows客户端深度解析与实战指南

跨平台USB设备共享神器&#xff1a;USB/IP Windows客户端深度解析与实战指南 【免费下载链接】usbip-win2 USB/IP Client for Windows 项目地址: https://gitcode.com/gh_mirrors/us/usbip-win2 在当今多设备协同工作的时代&#xff0c;USB/IP协议为Windows用户带来了革…

作者头像 李华
网站建设 2026/6/13 10:59:06

2026本地视频怎么去水印?实用本地视频去水印方法+软件推荐

日常保存的本地视频大多带有平台水印、logo标识、滚动字幕水印&#xff0c;不仅影响画面观感&#xff0c;二次剪辑、素材收藏使用时也十分受限。很多用户在寻找本地视频去水印方法时&#xff0c;常会遇到工具仅支持在线链接、处理画质压缩、操作复杂、隐私泄露等问题。2026年主…

作者头像 李华