手撕代码系列(四)
手写触发控制器 Scheduler
- • 当资源不足时将任务加入队列,当资源足够时,将等待队列中的任务取出执行
- • 任务调度器-控制任务的执行,当资源不足时将任务加入等待队列,当资源足够时,将等待队列中的任务取出执行
- • 在调度器中一般会有一个等待队列
queue
,存放当资源不够时等待执行的任务。 - • 具有并发数据限制,假设通过
max
设置允许同时运行的任务,还需要count
表示当前正在执行的任务数量。 - • 当需要执行一个任务 A 时,先判断
count==max
如果相等说明任务 A 不能执行,应该被阻塞,阻塞的任务放进queue
中,等待任务调度器管理。 - • 如果
count< max
说明正在执行的任务数没有达到最大容量,那么count++
执行任务 A,执行完毕后count--
。 - • 此时如果
queue
中有值,说明之前有任务因为并发数量限制而被阻塞,现在count < max
,任务调度器会将对头的任务弹出执行。
class Scheduler { constructor(max) { this.queue = []; this.max = max; this.count = 0; } add(time, order) { const promise = () => { return new Promise((resolve, reject) => { setTimeout(() => { console.log(order); resolve(); }, time); }); }; this.queue.push(promise); } start() { for (let i = 0; i < this.max; i++) { this.request(); } } request() { if (!this.queue.length || this.count >= this.max) return; this.count++; this.queue .shift()() .then(() => { this.count--; this.request(); }); } } // test: let scheduler = new Scheduler(2); scheduler.add(2000, '1'); scheduler.add(200, '2'); scheduler.add(500, '3'); scheduler.add(800, '4'); scheduler.add(1200, '5'); scheduler.start(); // 2 3 4 1 5
统计页面中前三个标签出现的个数
/** * 统计前三的标签 * * @logic * 1.先拿到所有标签的标签名 * 2.对每个标签进行统计 * 3.倒序 * 4.截取前三项即可 */ Object.entries( [...document.querySelectorAll('*')] .map(tag => tag.tagName) .reduce((ret, i) => { ret[i] = (ret[i] || 0) + 1; return ret; }, {}) ) .sort((a, b) => b[1] - a[1]) .slice(0, 3) .map(item => `${item[0]}: ${item[1]}`) .join(','); // test: // [ // ['SPAN', 451], // ['A', 135], // ['DIV', 106] // ] // 统计页面中使用到的标签 new Set([...document.querySelectorAll('*')].map(tag => tag.tagName)); // Set(37) {'HTML', 'RELINGO-APP', 'DIV', 'HEAD', 'META', …} // 统计每个标签使用的个数 Object.entries( [...document.querySelectorAll('*')] .map(tag => tag.tagName) .reduce((prev, next) => { prev[next] = (prev[next] || 0) + 1; return prev; }, {}) ); // test: // [ // ['HTML', 1] // ['RELINGO-APP', 2] // ['DIV', 106] // ['HEAD', 1] // ['META', 7] // ['TITLE', 1] // ['LINK', 71] // ['SCRIPT', 8] // ]
实现菲波那切数列 factorial
function factorial(n) { if (n <= 1) return 1; // return fibonacci(n - 1) + fibonacci(n - 2); return n * factorial(n - 1); } // test: console.log('factorial(5)', factorial(3)); // 6
lru-缓存
- • lru 是近期最少使用的缓存对象,核心是想要淘汰掉近期使用较少的对象
class LRUCache { constructor(capacity) { this.cache = new Map(); this.max = capacity; } get(key) { if (this.cache.has(key)) { let temp = this.cache.get(key); // 删除当前项 this.cache.delete(key); // 将当前项移到最前面 this.cache.set(key, temp); return temp; } return -1; } put(key, value) { if (this.cache.has(key)) { this.cache.delete(key); } else { // 如果缓存数 >= this.max 然后执行淘汰机制 // this.cache.keys().next().value:cache 中第一个值 if (this.cache.size >= this.max) { this.cache.delete(this.cache.keys().next().value); } } this.cache.set(key, value); } } // test: let lRUCache = new LRUCache(2); lRUCache.put(1, 1); // 缓存是 {1=1} lRUCache.put(2, 2); // 缓存是 {1=1, 2=2} lRUCache.get(1); // 返回 1 lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {3=3, 1=1} lRUCache.get(2); // 返回 -1 (未找到) lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3} lRUCache.get(1); // 返回 -1 (未找到) lRUCache.get(3); // 返回 3 lRUCache.get(4); // 返回 4 console.log(lRUCache.cache.size);
使用 setInterVal 实现 setTimeout
/** * @param {Function} fn 方法 * @param {Number} time 间隔时间 */ const MySetTimeout = (fn, time = 400) => { let timer = setInterval(() => { fn(); clearInterval(timer); }, time); }; // test: MySetTimeout(() => { console.log('12132'); }, 3000);
使用 setTimeout 实现 setInterVal
/** * @param {Function} fn 方法 * @param {Number} timeout 间隔时间 */ function MysetInterVal(fn, timeout = 1500) { let timer = null; const interval = () => { fn(); timer = setTimeout(interval, timeout); }; setTimeout(interval, timeout); return { cancel: () => { clearTimeout(timer); }, }; } // test: let { cancel } = MysetInterVal(() => console.log(454545), 1500); setTimeout(() => { cancel(); }, 4000);
特殊字符描述
•问题标注 Q:(question)
•答案标注 R:(result)
•注意事项标准:A:(attention matters)
•详情描述标注:D:(detail info)
•总结标注:S:(summary)
•分析标注:Ana:(analysis)
•提示标注:T:(tips)