点击上方蓝字关注前端真好玩,从此前端进阶不再难
干爆前端是笔者新搞的一个仓库,一网打尽前端面试、学习路径、优秀好文、面试资料等各类内容,帮助大家一年内拿到期望的 offer!
其中一部分内容是「每日更新一道大厂原题」,笔者前段时间靠着人脉收集了一波目前最新各个大厂的面试题,绝不是大规模传播的那种,适合有跳槽计划的读者学习。
目前参与人数众多,笔者建了个打卡群,每天都有数十人参与打卡学习,群内学习氛围相当浓厚,如果你也想参与学习的话可以扫描二维码,备注打卡。
这里是仓库地址:https://github.com/KieSun/fucking-frontend。目前内容包括大厂真题、十五万字面试资料及数百岗位的内推信息,内容还在持续更新,欢迎大家 star 关注。
公众号每周会整合真题及答案,以下是今天的内容:
第一题
页面上有三个按钮,分别为 A、B、C,点击各个按钮都会发送异步请求且互不影响,每次请求回来的数据都为按钮的名字。
请实现当用户依次点击 A、B、C、A、C、B 的时候,最终获取的数据为 ABCACB。
这道题目主要两个考点:
请求不能阻塞,但是输出可以阻塞。比如说 B 请求需要耗时 3 秒,其他请求耗时 1 秒,那么当用户点击 BAC 时,三个请求都应该发起,但是因为 B 请求回来的慢,所以得等着输出结果。
如何实现一个队列?
其实我们无需自己去构建一个队列,直接利用 promise.then
方法就能实现队列的效果了。
class Queue {
promise = Promise.resolve();
excute(promise) {
this.promise = this.promise.then(() => promise);
return this.promise;
}
}
const queue = new Queue();
const delay = (params) => {
const time = Math.floor(Math.random() * 5);
return new Promise((resolve) => {
setTimeout(() => {
resolve(params);
}, time * 500);
});
};
const handleClick = async (name) => {
const res = await queue.excute(delay(name));
console.log(res);
};
handleClick('A');
handleClick('B');
handleClick('C');
handleClick('A');
handleClick('C');
handleClick('B');
第二题
异步请求通过 Promise.all
处理,怎么让其中失败的所有请求重试。
Promise.all([A, B, C, D])
// 4 个请求完成后发现 AD 请求失败了,如果让 AD 请求重试
这个题目其实很简单,因为 Promise.all
中一个 promise
挂了就挂了,所以我们直接在接口上处理 catch
就行了。
看了些答案,结果是对的,但是处理方式是错误的。比如说在 resolve
中去判断是否要重试。一般我们业务中请求都是封装过的函数,出现错误肯定直接 reject
了,不可能 resolve
出来。
答案摘自 vandvassily
其他类似优秀答案:yancongwen
function request(name, count = 0) {
return new Promise((resolve, reject) => {
const isSuccess = Math.random() > 0.5;
console.log(`接口${name}: ${isSuccess}`);
setTimeout(() => {
isSuccess > 0.5 ? resolve(name) : reject(name);
}, Math.random() * 1000);
}).catch((err) => {
count++;
if (count > 2) {
return Promise.reject(`后端大爷${name}接口写的666`);
}
return request(name, count);
});
}
let queue = [request('A'), request('B'), request('C'), request('D')];
Promise.all(queue)
.then((arr) => {
console.log(arr);
})
.catch((err) => {
console.log(err);
});
第三题
/**
* @param input
* @param size
* @returns {Array}
*/
_.chunk(['a', 'b', 'c', 'd'], 2)
// => [['a', 'b'], ['c', 'd']]
_.chunk(['a', 'b', 'c', 'd'], 3)
// => [['a', 'b', 'c'], ['d']]
_.chunk(['a', 'b', 'c', 'd'], 5)
// => [['a', 'b', 'c', 'd']]
_.chunk(['a', 'b', 'c', 'd'], 0)
// => []
这道题目其实就是让大家实现一个 lodash 里的函数,这边我们需要注意的一个点是不能更改原数组,虽然题目没有提到,但是我们得想到这个。
笔者这里推荐几个答案,分别是不同的写法,难度从低到高吧。
首先是遍历的写法:
答案链接
function chunk(arr, num) {
if (num === 0) return [];
if (Array.isArray(arr) && typeof num === "number") {
let result = [];
let i = 0;
while (i < arr.length) {
result.push(arr.slice(i, i + num));
i += num;
}
return result;
} else {
console.log("params type error");
}
}
我们也可以使用 reduce
来解题:
答案链接
const chunk = (arr, len) => arr.reduce((pre, cur, index) => {
if (index % len === 0) {
pre.push([cur])
return pre
}
const temp = pre[pre.length - 1]
temp && temp.push(cur)
return pre
}, [])
甚至直接优化到一行:
答案链接
function chunk(arr, size){
return Array.from({length: (size = Number.parseInt(size)) ? Math.ceil(arr.length/size) : 0})
.map((a,i) => arr.slice(i*size, (i+1)*size))
}
如果觉得不错,素质三连、或者点个「赞」、「在看」都是对笔者莫大的支持,谢谢各位大佬啦~
我的付费社区「前端怎么玩」
在这里你能获得些什么?
我学习的路径,平时看到的好文章、想法、资料、新技术都会整理好分享出来,帮助你更快成长,开阔眼界,拓宽技术栈。
你的疑问,工作上、技术、职业等等无限次提问,不方便暴露隐私还可以匿名提问,我能回答的肯定会聊聊我的想法。
不定期的线上学习活动组织,打卡分享。
一月一期的高质量分享及答疑,包括简历修改、模拟面试等。
一个高质量的微信群。