webDevInterviewQuestions/algorithm/04-practical-scenarios.md
2026-01-19 09:43:07 +08:00

257 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 实际场景与逻辑题
## 1. 并发控制(限制并发请求数)
> **场景**批量上传文件如100张图片每次最多5个并发、网络爬虫控制请求频率、避免压垂服务器。
> **解决**:大量异步任务同时发起导致浏览器卡顿或服务端拒绝服务。
```js
async function limitConcurrency(tasks, limit) {
const results = [];
const executing = [];
for (const [index, task] of tasks.entries()) {
const p = Promise.resolve().then(() => task()).then(res => {
results[index] = res;
executing.splice(executing.indexOf(p), 1);
});
executing.push(p);
if (executing.length >= limit) {
await Promise.race(executing);
}
}
await Promise.all(executing);
return results;
}
// 使用示例
const tasks = urls.map(url => () => fetch(url));
await limitConcurrency(tasks, 3); // 最多3个并发
```
### 异步任务调度器
```js
class Scheduler {
constructor(limit) {
this.limit = limit;
this.queue = [];
this.running = 0;
}
add(promiseCreator) {
return new Promise((resolve, reject) => {
this.queue.push({ promiseCreator, resolve, reject });
this.run();
});
}
run() {
while (this.running < this.limit && this.queue.length) {
const { promiseCreator, resolve, reject } = this.queue.shift();
this.running++;
promiseCreator()
.then(resolve, reject)
.finally(() => { this.running--; this.run(); });
}
}
}
```
---
## 2. 缓存函数Memoization
> **场景**计算密集型函数结果缓存如斐波那契、API 请求缓存、React useMemo 原理。
> **解决**:相同输入重复计算浪费性能,用空间换时间。
```js
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// 支持过期时间
function memoizeWithTTL(fn, ttl = 60000) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
const cached = cache.get(key);
if (cached && Date.now() - cached.time < ttl) {
return cached.value;
}
const result = fn.apply(this, args);
cache.set(key, { value: result, time: Date.now() });
return result;
};
}
```
---
## 3. 解析 URL 参数
> **场景**从链接提取分享参数、跟踪渠道来源utm_source、路由参数解析。
> **解决**:将 URL 查询字符串转换为结构化对象,方便业务使用。
```js
function parseQuery(url) {
const query = url.split('?')[1] || '';
return query.split('&').reduce((acc, pair) => {
const [key, value] = pair.split('=').map(decodeURIComponent);
if (key) {
acc[key] = acc[key]
? [].concat(acc[key], value)
: value;
}
return acc;
}, {});
}
// 使用正则
function parseQueryRegex(url) {
const result = {};
url.replace(/[?&]([^=&#]+)=([^&#]*)/g, (_, key, value) => {
result[decodeURIComponent(key)] = decodeURIComponent(value);
});
return result;
}
// 示例: "https://example.com?a=1&b=2&a=3"
// => { a: ['1', '3'], b: '2' }
```
---
## 4. DOM 查找最近公共祖先
> **场景**:事件委托的目标元素判断、富文本编辑器选区处理、拖拽边界计算。
> **解决**:在 DOM 树中找到两个节点的最近共同父级。
```js
function findCommonAncestor(node1, node2) {
const ancestors = new Set();
// 收集 node1 的所有祖先
let current = node1;
while (current) {
ancestors.add(current);
current = current.parentNode;
}
// 查找 node2 的祖先中第一个在 ancestors 中的节点
current = node2;
while (current) {
if (ancestors.has(current)) return current;
current = current.parentNode;
}
return null;
}
// 原生方法(现代浏览器)
// node1.compareDocumentPosition(node2)
```
---
## 5. 懒加载/无限滚动
> **场景**:电商商品列表、社交信息流、图片画廊、新闻列表。
> **解决**:首屏加载慢、一次性加载大量数据卡顿的问题。
```js
// IntersectionObserver 实现懒加载
function lazyLoad(selector) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll(selector).forEach(img => observer.observe(img));
}
// 无限滚动
function infiniteScroll(container, loadMore) {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting) loadMore();
});
// 监听底部占位元素
const sentinel = document.createElement('div');
container.appendChild(sentinel);
observer.observe(sentinel);
}
```
---
## 6. LRU 缓存
> **场景**浏览器缓存淘汰、图片缓存池、Redis 内存管理、keep-alive 组件缓存。
> **解决**:内存有限时如何淘汰最久未使用的数据,保留热点数据。
```js
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
if (!this.cache.has(key)) return -1;
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
put(key, value) {
if (this.cache.has(key)) this.cache.delete(key);
this.cache.set(key, value);
if (this.cache.size > this.capacity) {
this.cache.delete(this.cache.keys().next().value);
}
}
}
```
---
## 7. 大数相加
> **场景**:订单号/交易号处理、金融精确计算、超出 JS Number 范围的计算。
> **解决**JS 数字最大安全整数 2^53-1 限制,大数运算精度丢失问题。
```js
function addBigNumbers(a, b) {
const maxLen = Math.max(a.length, b.length);
a = a.padStart(maxLen, '0');
b = b.padStart(maxLen, '0');
let carry = 0, result = '';
for (let i = maxLen - 1; i >= 0; i--) {
const sum = +a[i] + +b[i] + carry;
result = (sum % 10) + result;
carry = Math.floor(sum / 10);
}
return carry ? carry + result : result;
}
// 示例: addBigNumbers("12345678901234567890", "98765432109876543210")
```