发布于 2024 年 2 月 26 日,星期一
"手撕代码系列(四)"这个标题暗示了博客内容将深入探讨前端开发中的代码实现细节。"手撕"一词通常用于形容对代码进行深入剖析和手动实现,而非简单地调用库或框架。"系列"表明这是一个持续的系列文章,每篇都聚焦于不同的代码实现或技术点。"四"则指这是该系列的第四篇文章。综合来看,该标题传达了作者将通过具体代码示例,详细讲解前端开发中的某个技术或功能实现,强调手动编写和理解代码的重要性,而非依赖现成的解决方案。这种深入剖析有助于读者更好地掌握前端开发的底层原理和技巧。
系列首发于公众号『非同质前端札记』https://mp.weixin.qq.com/s?__biz=MzkyOTI2MzE0MQ==&mid=2247485576&idx=1&sn=5ddfe93f427f05f5d126dead859d0dc8&chksm=c20d73c2f57afad4bbea380dfa1bcc15367a4cc06bf5dd0603100e8bd7bb317009fa65442cdb&token=1071012447&lang=zh_CN#rd ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。
queue
,存放当资源不够时等待执行的任务。max
设置允许同时运行的任务,还需要count
表示当前正在执行的任务数量。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]
// ]
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
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);
/**
* @param {Function} fn 方法
* @param {Number} time 间隔时间
*/
const MySetTimeout = (fn, time = 400) => {
let timer = setInterval(() => {
fn();
clearInterval(timer);
}, time);
};
// test:
MySetTimeout(() => {
console.log('12132');
}, 3000);
/**
* @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)