一次羞愧难当的阿里前端笔试经历,本次换工作不会再寻求任何阿里工作机会!
来源:公众号【前端从进阶到入院】
https://mp.weixin.qq.com/s/8Gnx2d_Zo4Rwm2en0UOetg
本文记录为非技术类文章,旨在记录一个让我无地自容的故事,鞭笞自己能知耻而后勇。
背景
故事要从 2020 年末讲起,届时正值我司方向变动期,以往工作内容或将永远舍弃,我多少也有些失望和迷茫,于是起了挪窝的心思。
恰巧,钉钉团队的东明在不久后(2021年初)从简历库中捞到了我,问我是否有换工作的意愿,我欣然告诉他年后会考虑换工作。
期间偶尔准备...时间来到2021年二月19号(今天),春节前两天首面的字节跳动,与我谈好了 offer。我在感慨字节效率时,忽然想到如果还不内推阿里,或许在入职前没办法面完。
于是我匆匆忙忙地联系了东明,希望他帮我内推简历,并告诉他已经拿到了字节的 offer(不算节假日就几天时间),他非常上心并愿意帮我加急内推,我有些感动,告诉他如果流程来得及、或则加急比较麻烦就不需要加急。
他依然帮我加急了,但我没想到的是,这在几个小时后会成为我无比羞愧的原因之一。
一刻钟后,成都文档这边的前端负责人绝云联系了我,询问我什么时间方便在线笔试,我有些受宠若惊,就像是特意为我开了一个独立的跑道,他们为一个应聘者劳心劳力。
于是我略作思索,就把笔试时间定在了今晚9点。
历程
阅题
9点左右,我收到了笔试题连接,一个半小时两道笔试题,题目如下:
/** 1. 信号灯控制器
用 React 实现一个信号灯(交通灯)控制器,要求:
1. 默认情况下,
1.1. 红灯亮20秒,并且最后5秒闪烁
1.2. 绿灯亮20秒,并且最后5秒闪烁
1.3. 黄灯亮10秒
1.4. 次序为 红-绿-黄-红-绿-黄
2. 灯的个数、颜色、持续时间、闪烁时间、灯光次序都可配置,如:
lights=[{color: '#fff', duration: 10000, twinkleDuration: 5000}, ... ]
*/
import React from 'react'
import ReactDOM from 'react-dom'
class TrafficLightItem extends React.Component {
}
/** 2. 寻找特定 IP
IPV4 的 IP 地址是32位的二进制数,为增强可读性,通常我们以8位为1组进行分割,
用十进制来表示每一部分,并用点号连接,譬如 192.168.1.1。显然,存在这样的 IP 地址,
0到9十个数字各出现一次。具备这样特征的 IP 地址里,表示成二进制数时,二进制数左右对称
(也就是“回文”,表示成32位二进制不省略0)的情况有几种,分别是哪些?要求性能尽可能高
*/
我查阅了题目,很快就发现了对我而言的难点:
第一道题要使用 react ,而我几乎没有使用过,但我相信这并不会成为太大的阻碍,因试题并不复杂 第二道题比较晦涩,我一时没有好的思路去解决
所以我制定好了我的答题计划:
完成第一道题 第二道做一部分,来不及做的部分注释思路
做题
我想首先要能跑得起来 react ,才能知道哪些语法能写,所以我 Google 了 react ,在官网找到了快速起步 npx create-react-app test1
。
我打开项目,粗略看了下结构便快速地新建了 components/
和 .js/.css
文件,但下一刻我就遇到了第一个预料之外的问题,初始化的项目使用的是 function 组件,而题目使用的却是 class 组件,我想模仿脚手架模板写的心思有些许受挫。
还好我记得我看过 react 使用 class 组件的视频,我不用像无头苍蝇一样去翻文档,于是我打开慕课网,找到了我历史记录中的 react 入门视频,从中我找到了我想要的 class component 的写法(借助 vscode 的一个 react snippet 的插件),并且快速浏览了我之后会用到的 props 写法。
由于初始化阶段出了意外,所以我一直注意着时间,发现等我写好主体结构、props 传参后,才过了十余分钟,所以并没有认为事态有过失控。
我发现题目提供的数据结构并不能保证路灯完全可配置,因为灯光颜色存在三种状态,各个灯光的时间也应该单独控制,所以我扩展了 props 传参和模拟数据,并且完成了无逻辑状态下组件的展示。
虽然有些不顺利,但此时我并未感到焦急,因为余下的时间还有将近 70 分钟,但接下来所发生的事就打破了我所有的预期、或则说幻想。
TS 报错
路灯的模拟数据要是数组,所以我拆分了组件 TrafficLight
和TrafficLightItem
,并且按照我记忆中我看过的 JSX 语法使用了 for 循环去生成多个TrafficLightItem
,但这一步报错了...一个 TS 的报错,而我明明使用的是 js...
截图为笔试后自己复现) 这个问题我试了很多方法:
vscode 提示 lights
是any
类型,我想是不是需要明确定义为 Array 才不会报错,但 js 并不能定义类型我怀疑是否是 HMR 有问题,编辑器也胡乱报了一个错,所以我重启工程,在浏览器上仍然报错 我怀疑是否是 lights
prop 没有传递过来,所以我直接把lights
定义在当前组件,甚至不定义变量直接使用模拟数据(一个Array)执行map
方法
最终尝试在 return 中加一个根节点,就不再报错了...
动态修改样式
要动态切换颜色,我需要知道 react 如何动态修改 style 样式,我尝试了几种写法,最终还是靠 Google 解决
更新视图
要动态切换颜色,我需要知道 react 如何更新视图,事实上我知道是通过 setState
函数。
但该函数如何调用,state
肯定又不能是普通变量,所以我又只能去 Google ,并且花了很长时间去调整、尝试 setState
应该放到哪里去调用的问题(起初我放到 render
函数中,视图卡住无法加载,我才意识到不能这么做)。
最终通过这篇文章[1]才解决了我的各种 this
、setState
、state
问题
以上种种处理完毕,时间已然没了大半,还剩半个小时我焦急无比。
但我并没有放弃,或许当时的我认为我已然能做好第一题,或许只是没有足够的时间做第二道题而已。
但事实往往更加残酷,之后 10 分钟,我写好了三个状态切换相关的函数:闪烁函数twinkle
、初始化状态函数 init
和循环进行初始化的函数 lightInterval
,并处理定时器中 this 指向的问题,但我想要的路灯状态切换并没有出现。
而后 15 分钟便是我最最煎熬的调试时间,我焦急又麻木的一次又一次的尝试,但就是没有解决一个问题。我的状态切换一直没有出现,我知道是异步导致的问题,但我并不知道为什么会这样,我的思维似乎在写完关键函数后就进入了停滞状态...
10点25分,面试官提醒我准备交卷,我还精神恍惚地挣扎了两分钟,最终在10点28交卷,并通过钉钉艰难地向面试官提出放弃。
代码
以下就是一个工作将近五年,自诩功底不错的前端交出的试卷原样:
/** 1. 信号灯控制器
用 React 实现一个信号灯(交通灯)控制器,要求:
1. 默认情况下,
1.1. 红灯亮20秒,并且最后5秒闪烁
1.2. 绿灯亮20秒,并且最后5秒闪烁
1.3. 黄灯亮10秒
1.4. 次序为 红-绿-黄-红-绿-黄
2. 灯的个数、颜色、持续时间、闪烁时间、灯光次序都可配置,如:
lights=[{color: '#fff', duration: 10000, twinkleDuration: 5000}, ... ]
*/
import React from 'react'
import ReactDOM from 'react-dom'
class TrafficLightItem extends React.Component {
constructor(props) {
super(props);
const {
stopColor = "red",
passColor = "green",
pendingColor = "yellow",
stopDuration = 20000,
stopTwinkleDuration = 5000,
passDuration = 20000,
passTwinkleDuration = 5000,
pendingDuration = 10000,
} = this.props.config;
this.stopColor = stopColor
this.passColor = passColor
this.pendingColor = pendingColor
this.stopDuration = stopDuration
this.stopTwinkleDuration = stopTwinkleDuration
this.passDuration = passDuration
this.passTwinkleDuration = passTwinkleDuration
this.pendingDuration = pendingDuration
this.state = {
coolr: this.stopColor
};
}
// initial
async init() {
// stop color
await setTimeout(() => {}, this.stopDuration - this.stopTwinkleDuration);
// stop color twinkle
await this.twinkle(this.stopColor, this.stopTwinkleDuration)
// switch to pass color
this.setState({
color: this.passColor,
});
await setTimeout(() => {}, this.passDuration - this.passTwinkleDuration);
// pass color twinkle
await this.twinkle(this.passColor, this.passTwinkleDuration)
// switch to pending color
this.setState({
color: this.pendingColor,
});
}
// interval
async lightInterval() {
this.init()
let totalDuration = this.stopDuration + this.passDuration + this.pendingDuration;
setInterval(this.init, totalDuration);
}
// 闪烁
async twinkle(color, duration) {
let _timer
await setTimeout(() => {
let cur = color
_timer = setInterval(() => {
if (cur === color) {
this.setState({
color: 'black'
})
} else {
this.setState({
color
})
}
}, 1000);
}, duration)
clearInterval(_timer)
}
componentDidMount() {
this.timer = this.lightInterval();
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return (
<div class="light" style={{ backgroundColor: this.state.color }}></div>
);
}
}
class TrafficLight extends React.Component {
render() {
const lights = this.props.lights;
return (
<div>
{lights.map((light, index) => (
<TrafficLightItem key={index} config={light}></TrafficLightItem>
))}
</div>
);
}
}
ReactDOM.render(<TrafficLight/>, document.body);
反思
15分钟也没解出的 bug 其实很简单,尘埃落定之后很快就发现了问题,有两个:
我用 await
去等待宏任务闪烁函数中逻辑有些混乱,定义了 cur
却没修改他的值。
导致第一个问题的原因恐怕还是我写得太少,如此离谱的、用当朝剑去斩前朝官的事,我想不到还能找什么借口。
等歉意和客套处理妥当,事实上我也很快解决了问题——新增了一个用于实现异步等待的 wait
函数。
总结与感悟
决定写这篇文章时,我心中还满是羞愧和难过。
羞愧在于走了特殊通道,但表现得像一个小丑,难过在于,辜负了别人的信任。
所以我想把不堪记录下来,督促自己今后学习稍多一点尽量避免这样的事故,也是想要写出来告诉和我接触的东明和绝云,不要因为个例而沮丧,请一如既往相信应聘者。
正视自己的不堪,我才能变得强大。
额外说明:本文无意拐弯抹角碰瓷阿里,在此也保证本次换工作不会再寻求任何阿里工作机会
ssh 注:
金三银四来了,可能部分同学会有换坑的想法,本文是一个相对反面的教材,希望能让大家吸取一些经验。
准备好之前不要轻易接受面试,不要冲动,大公司面试都会留下评价记录。
对于自己不熟悉的技术不要过分自信,可以尝试要求面试官切换到自己熟悉的技术栈上。