手撕代码系列(四)

简介: 手撕代码系列(四)

手撕代码系列(四)


手写触发控制器 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)

目录
相关文章
|
JavaScript 前端开发
【面试题】最详尽的 JS 原型与原型链终极详解(一)
【面试题】最详尽的 JS 原型与原型链终极详解(一)
323 0
|
机器学习/深度学习 安全 算法
技术焦点篇|Cheetah猎豹及其在隐语中的实现
技术焦点篇|Cheetah猎豹及其在隐语中的实现
1306 1
|
10月前
|
前端开发 JavaScript UED
什么是组件化设计
【10月更文挑战第22天】什么是组件化设计
|
12月前
|
网络协议 安全 物联网
探索未来网络:IPv6的演进与应用
本文深入探讨了互联网协议第6版(IPv6)的发展历程、技术特点以及在各领域的应用前景。通过对IPv4面临的问题进行分析,阐明了IPv6出现的必要性及其在地址空间扩展、安全性提升和自动配置等方面的显著优势。结合当前技术趋势和应用案例,展望了IPv6在未来网络中的发展潜力,为相关领域的研究和实践提供了参考。
|
存储 Linux C++
网易面试:手撕定时器
网易面试:手撕定时器
213 1
|
算法 C语言 开发者
C语言手撕实战代码_单链表
本文档详细介绍了使用C语言实现单链表的各种基本操作和经典算法。内容涵盖单链表的构建、插入、查找、合并及特殊操作,如头插法和尾插法构建单链表、插入元素、查找倒数第m个节点、合并两个有序链表等。每部分均配有详细的代码示例和注释,帮助读者更好地理解和掌握单链表的编程技巧。此外,还提供了判断子链、查找公共后缀等进阶题目,适合初学者和有一定基础的开发者学习参考。
138 2
|
数据管理 数据处理 数据库
数据库中的 ACID 属性详解
【8月更文挑战第31天】
781 0
|
索引
【LeetCode刷题】二分查找:山脉数组的峰顶索引、寻找峰值
【LeetCode刷题】二分查找:山脉数组的峰顶索引、寻找峰值
168 1
若依修改,集成mybatisplus报错,若依集成mybatisplus,总是找不到映射是怎么回事只要是用mp的方法就找报,改成mybatisPlus配置一定要改
若依修改,集成mybatisplus报错,若依集成mybatisplus,总是找不到映射是怎么回事只要是用mp的方法就找报,改成mybatisPlus配置一定要改
|
XML Java 调度
什么是时间轮?
时间轮是一种用于任务调度和时间管理的数据结构,尤其适合处理大量定时任务的场景,如网络服务器或实时系统。它由一个圆形数组构成,每个槽代表固定时间间隔,任务根据执行时间添加到相应槽。时间推进时,指针移动并执行到期任务。时间轮具有高效性和简单性,插入和删除操作接近常数时间复杂度。层级时间轮可扩展处理更大时间范围和精度。在Spring Boot中,可以使用Netty的`HashedWheelTimer`实现高效定时任务管理。
279 0