一、观察者模式 vs 中介者模式 vs 发布-订阅
🔍 底层机制

核心差异:
- 观察者:直接耦合(Subject持有Observer引用)
- 中介者:通过中介解耦(Colleagues不直接通信)
- 发布订阅:通过事件总线完全解耦
🛠️ 实现对比
js
// 观察者模式
class Subject {
observers = []
add(o) { this.observers.push(o) }
notify() { this.observers.forEach(o => o.update()) }
}
// 发布订阅
class EventBus {
events = {}
on(type, fn) { (this.events[type] ||= []).push(fn) }
emit(type, data) { this.events[type]?.forEach(fn => fn(data)) }
}
🌐 应用场景
模式 | 典型案例 | 反例场景 |
---|---|---|
观察者 | Vue响应式系统 | 跨组件深层通信 |
中介者 | 聊天室(Room作为中介) | 简单的一对一通信 |
发布订阅 | 全局事件总线 | 需要严格顺序的事件流 |
💡 举一反三
- Redux属于哪种模式?(发布订阅的变体)
- Node.js的EventEmitter实现原理
二、HTTP连接复用机制
🔍 底层机制
sequenceDiagram
participant Browser
participant Server
Browser->>Server: TCP握手 (SYN)
Server->>Browser: SYN-ACK
Browser->>Server: ACK
rect rgb(200, 220, 255)
Browser->>Server: HTTP/1.1请求1 (keep-alive)
Server->>Browser: 响应1
Browser->>Server: HTTP/1.1请求2 (复用连接)
Server->>Browser: 响应2
end
rect rgb(255, 220, 200)
Browser->>Server: HTTP/2多路复用
Note over Browser,Server: 单连接并行传输
end
关键差异:
- HTTP/1.1:串行请求(队头阻塞)
- HTTP/2:二进制分帧 + 多路复用
🛠️ 配置对比
http
// HTTP/1.1 头部
Connection: keep-alive
Keep-Alive: timeout=5, max=1000
// HTTP/2 自动复用
:method: GET
:scheme: https
:path: /api/data
🌐 性能优化
js
// 检测连接复用
const connection = performance.getEntriesByType('navigation')[0]
console.log(connection.nextHopProtocol) // "h2" 或 "http/1.1"
三、CSS Position全解析
🔍 底层机制
flowchart TD
A[position属性] --> B[static]
A --> C[relative]
A --> D[absolute]
A --> E[fixed]
A --> F[sticky]
C --> G[占据原空间]
D --> H[脱离文档流]
F --> I[吸附定位]
I --> J[阈值触发]
J --> K[top/right/bottom/left]
🛠️ sticky实战
css
.table-header {
position: sticky;
top: 0;
background: white;
z-index: 10;
}
/* 兼容性处理 */
@supports not (position: sticky) {
.table-header { position: fixed; }
}
🌐 应用场景
定位方式 | 典型用例 | 注意事项 |
---|---|---|
sticky | 表头/侧边栏吸附 | 需父级无overflow:hidden |
absolute | 弹窗/下拉菜单 | 最近定位祖先元素 |
fixed | 返回顶部按钮 | iOS键盘弹出时可能失效 |
四、浏览器事件流与代理
🔍 底层机制
flowchart TD
A[事件触发] --> B[捕获阶段]
B --> C[目标阶段]
C --> D[冒泡阶段]
E[事件代理] --> F[绑定到父级]
F --> G[通过target判断]
G --> H[减少监听器数量]
🛠️ 事件代理实现
js
// 动态列表的事件代理
ul.addEventListener('click', (e) => {
if (e.target.matches('li.item')) {
handleItemClick(e.target.dataset.id)
}
})
// 性能对比
// 直接绑定: O(n)个监听器
// 事件代理: O(1)个监听器
🌐 优缺点分析
优点:
- 减少内存占用
- 支持动态元素
- 简化初始化
缺点:
- 事件类型限制(如focus/blur不支持冒泡)
- 事件层级过深时target可能不准确
五、this绑定规则全解
🔍 底层机制
flowchart TD
A[this绑定] --> B[默认绑定]
A --> C[隐式绑定]
A --> D[显式绑定]
A --> E[new绑定]
A --> F[箭头函数]
B --> G[严格模式undefined]
C --> H[对象方法调用]
D --> I[call/apply/bind]
E --> J[构造函数]
F --> K[词法作用域]
🛠️ 优先级排序
js
const obj = {
fn: function() {
console.log(this)
}
}
// 优先级:new > 显式 > 隐式 > 默认
new obj.fn() // this指向新对象
obj.fn.call(window) // this指向window
obj.fn() // this指向obj
🌐 经典陷阱
js
// 回调函数丢失this
setTimeout(obj.fn, 100) // this指向window
// 解决方案
setTimeout(obj.fn.bind(obj), 100)
// 或
setTimeout(() => obj.fn(), 100)
六、表单跨域深度解析
🔍 底层机制
sequenceDiagram
participant Browser
participant SiteA
participant SiteB
Browser->>SiteA: 加载页面
Browser->>SiteB: 表单POST action="SiteB"
SiteB->>Browser: 返回302重定向
Note over Browser: 浏览器自动跟随重定向
SiteB->>Browser: 最终响应
🛠️ 跨域方案对比
方案 | 是否支持 | 实现方式 |
---|---|---|
表单POST | ✅ | action指向跨域地址 |
AJAX提交 | ❌ | 需CORS或JSONP |
隐藏iframe | ✅ | target指向iframe |
🌐 安全限制
html
<!-- 允许跨域提交但无法读取响应 -->
<form action="https://api.cross.com/submit" method="POST">
<input name="data" value="test">
</form>
<!-- 现代方案:fetch + CORS -->
fetch('https://api.cross.com/submit', {
method: 'POST',
body: new FormData(form),
credentials: 'include'
})
七、Promise vs async/await
🔍 底层机制
flowchart LR
A[Promise] --> B[微任务队列]
C[async/await] --> D[生成器+Promise]
D --> E[await暂停执行]
E --> F[Promise.resolve]
F --> G[恢复执行]
🛠️ 语法对比
js
// Promise链
fetch('/api')
.then(r => r.json())
.then(data => console.log(data))
.catch(err => console.error(err))
// async/await
try {
const r = await fetch('/api')
const data = await r.json()
console.log(data)
} catch(err) {
console.error(err)
}
🌐 性能差异
- async/await本质是Promise的语法糖
- 错误处理更直观(try/catch)
- 调试时调用栈更清晰
八、搜索防抖实现
🔍 底层机制
flowchart TD
A[输入事件] --> B{是否等待中}
B -->|是| C[重置计时器]
B -->|否| D[启动计时器]
D --> E[延迟执行]
E --> F[发送请求]
🛠️ 实现方案
js
// 基础防抖
function debounce(fn, delay) {
let timer = null
return function(...args) {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}
// React Hook版本
function useDebounce(value, delay) {
const [debounced, setDebounced] = useState(value)
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay)
return () => clearTimeout(timer)
}, [value, delay])
return debounced
}
🌐 优化策略
- 立即执行版本(leading edge)
- 取消功能(cancel方法)
- 最大等待时间(throttle + debounce混合)
九、中文搜索请求处理
🔍 底层机制
flowchart TD
A[输入中文] --> B[URL编码]
B --> C[encodeURIComponent]
C --> D[UTF-8字节]
D --> E[%E4%B8%AD%E6%96%87]
F[服务端] --> G[decodeURIComponent]
G --> H[还原中文]
🛠️ 实现方案
js
// 现代浏览器自动处理
const keyword = '前端面试'
fetch(`/api/search?q=${keyword}`) // 自动编码
// 手动处理
const encoded = encodeURIComponent(keyword) // "%E5%89%8D%E7%AB%AF%E9%9D%A2%E8%AF%95"
const decoded = decodeURIComponent(encoded)
// POST方案(避免URL长度限制)
fetch('/api/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ keyword })
})
🌐 兼容性处理
js
// IE兼容
function encodeChinese(str) {
return encodeURIComponent(str)
.replace(/[!'()*]/g, c => `%${c.charCodeAt(0).toString(16)}`)
}
十、并发请求控制
🔍 底层机制
flowchart TD
A[请求数组] --> B[并发池]
B --> C[最大并发数限制]
C --> D[任务队列]
D --> E[完成一个补充一个]
F[Promise.all] --> G[全部并发]
F --> H[任一失败即失败]
I[Promise.allSettled] --> J[等待全部完成]
J --> K[不短路]
🛠️ 实现方案
js
// 并发池控制
async function concurrentRequest(urls, max = 5) {
const results = []
const executing = []
for (const url of urls) {
const p = fetch(url).then(res => res.json())
results.push(p)
if (urls.length >= max) {
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
executing.push(e)
if (executing.length >= max) {
await Promise.race(executing)
}
}
}
return Promise.all(results)
}
// 使用示例
const urls = Array.from({length: 20}, (_,i) => `/api/data/${i}`)
const data = await concurrentRequest(urls, 3)
🌐 高级控制
js
// 带进度回调
async function* concurrentWithProgress(urls, max) {
let completed = 0
const update = () => yield { completed: ++completed, total: urls.length }
// 实现略...
}