4.9 KiB
4.9 KiB
实际场景与逻辑题
1. 并发控制(限制并发请求数)
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个并发
异步任务调度器
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)
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 参数
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 查找最近公共祖先
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. 懒加载/无限滚动
// 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 缓存
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. 大数相加
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")