前言

系列首发于公众号『前端进阶圈』 ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。

手撕代码系列(四)

手写触发控制器 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); // 返回 1lRUCache.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); // 返回 3lRUCache.get(4); // 返回 4console.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);

特殊字符形容:

  1. 问题标注 Q:(question)
  2. 答案标注 R:(result)
  3. 注意事项规范:A:(attention matters)
  4. 详情形容标注:D:(detail info)
  5. 总结标注:S:(summary)
  6. 剖析标注:Ana:(analysis)
  7. 提醒标注:T:(tips)

    往期举荐:

  8. 前端面试实录HTML篇
  9. 前端面试实录CSS篇
  10. JS 如何判断一个元素是否在可视区域内?
  11. Vue2、3 生命周期及作用?
  12. 排序算法:QuickSort
  13. 箭头函数与一般函数的区别?
  14. 这是你了解的CSS选择器权重吗?
  15. JS 中 call, apply, bind 概念、用法、区别及实现?
  16. 罕用位运算办法?
  17. Vue数据监听Object.definedProperty()办法的实现
  18. 为什么 0.1+ 0.2 != 0.3,如何让其相等?
  19. 聊聊对 this 的了解?
  20. JavaScript 为什么要进行变量晋升,它导致了什么问题?

    最初:

  21. 欢送关注 『前端进阶圈』 公众号 ,一起摸索学习前端技术......
  22. 公众号回复 加群 或 扫码, 即可退出前端交流学习群,一起高兴摸鱼和学习......
  23. 公众号回复 加好友,即可添加为好友