# 实际场景与逻辑题 ## 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") ```