秋招开始以来面了几家公司,每次遇到手写题都很头疼,算法题还好,前端的手写题是真的要我老命,大部分直接当场尬住,感觉自己还是太菜了...甚至怀疑自己到底能不能干前端,在这里简单记录一下遇到的题目和解法。
1.最大并发请求队列 (猿辅导)
题目:有多个请求需要发出,存在input
数组中,请实现一个限制最大并发数量为2的请求方法,将请求的返回保存在output
数组,请求方法为fetch(url,callback)
。
解答:
这里有两种思路,一种是将数组分割为两个一组的多个数组,每次传入一个数组,用promise.all
的方法,当两个请求都返回了再调用下一个,但这种方法的局限性是,其中某一个请求很慢,就会阻塞整个队列。
另一种思路是维护一个请求队列,利用递归的方法不停的推入请求,可设置任意最大并发数,具体代码如下:
function handleFetchQueue(input, max) {
const urlCount = input.length; // 请求总长度,用于判断边界
const requestsQueue = []; // 请求队列
const output = []; // 结果
let i = 0;
const handleRequest = (url) => {
const req = fetch(url,(res)=>{
const len = output.push(res);
if (len < urlCount && i + 1 < urlCount) {
requestsQueue.shift(); // 请求成功后释放位置
handleRequest(input[++i]) // 控制何时进入下一次
} else if (len === urlCount) {
return output;
}
})
if (requestsQueue.push(req) < max) { //队列满了就不递归到下一个
handleRequest(input[++i]);
}
}
handleRequest(input[i]);
}
2.实现一个eventBus (字节跳动、猿辅导)
题目:手动实现事件注册和监听,即vue中的emit,on,off,once
解答:
class EventBus{
constructor(){
this.event=Object.create(null);
};
//注册事件
on(name,fn){
if(!this.event[name]){
//一个事件可能有多个监听者
this.event[name]=[];
};
this.event[name].push(fn);
};
//触发事件
emit(name,...args){
//给回调函数传参
this.event[name]&&this.event[name].forEach(fn => {
fn(...args)
});
};
//只被触发一次的事件
once(name,fn){
//在这里同时完成了对该事件的注册、对该事件的触发,并在最后取消该事件。
const cb=(...args)=>{
//触发
fn(...args);
//取消
this.off(name,fn);
};
//监听
this.on(name,cb);
};
//取消事件
off(name,offcb){
if(this.event[name]){
let index=this.event[name].findIndex((fn)=>{
return offcb===fn;
})
this.event[name].splice(index,1);
if(!this.event[name].length){
delete this.event[name];
}
}
}
}
3.实现简单的模板编译 (字节跳动)
题目:输入一个html页面,和已经注册的数据,将页面的相应数据部分替换为数据对象的相应部分:
//输入
const tmp = `
<h1>{{person.name}}</h1>
<address>{{person.address}}</address>
<samll>{{person.mather}}</samll>
`;
//需要编写render函数
const html = render(tmp, {
person: {
name: 'petter',
address: '409 Brookview Drive',
},
});
//期望的输出
const expect = `
<h1>petter</h1>
<address>409 Brookview Drive</address>
`
解答:
const tmp = `<h1>{{person.name}}</h1>
<address>{{person.address}}</address>
<small>{{person.mother}}</small>
`
function render(tmp, root) {
let newTemp = tmp;
function work(node, str) {
for (let key in node) {
if (typeof node[key] === 'object') {
str += key + '.'
work(node[key], str)
str = str.substring(0, str.length - key.length - 1);
}
else {
newTemp = newTemp.replace('{{' + str + key + '}}', node[key]);
}
}
}
work(root, '');
newTemp = newTemp.replace(/\{\{((?:.|\r?\n)+?)\}\}/g, '')
console.log(newTemp)
}
render(tmp, {
person: {
name: 'petter',
address: '409 brookview'
}
})