共计 3831 个字符,预计需要花费 10 分钟才能阅读完成。
前言
系列首发于公众号『前端进阶圈』,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。
手撕代码系列(四)
手写触发控制器 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)
往期举荐:
- 前端面试实录 HTML 篇
- 前端面试实录 CSS 篇
- JS 如何判断一个元素是否在可视区域内?
- Vue2、3 生命周期及作用?
- 排序算法:QuickSort
- 箭头函数与一般函数的区别?
- 这是你了解的 CSS 选择器权重吗?
- JS 中 call, apply, bind 概念、用法、区别及实现?
- 罕用位运算办法?
- Vue 数据监听 Object.definedProperty()办法的实现
- 为什么 0.1+ 0.2 != 0.3,如何让其相等?
- 聊聊对 this 的了解?
-
JavaScript 为什么要进行变量晋升,它导致了什么问题?
最初:
- 欢送关注『前端进阶圈』公众号,一起摸索学习前端技术 ……
- 公众号回复 加群 或 扫码, 即可退出前端交流学习群,一起高兴摸鱼和学习 ……
- 公众号回复 加好友,即可添加为好友
正文完