一次無地自容的阿里前端筆試經(jīng)歷!(真實(shí)事故)

源 / 前端從進(jìn)階到入院 文 / 匿名
本文記錄為非技術(shù)類文章,旨在記錄一個(gè)讓我無地自容的故事,鞭笞自己能知恥而后勇。
故 事 背 景
要說是故事,準(zhǔn)確的說應(yīng)該叫事故;
這事兒要從 2020 年末講起,屆時(shí)正值我司方向變動(dòng)期,以往工作內(nèi)容或?qū)⒂肋h(yuǎn)舍棄,我多少也有些失望和迷茫,于是起了挪窩的心思。
恰巧,釘釘團(tuán)隊(duì)的東明在不久后(2021年初)從簡(jiǎn)歷庫(kù)中撈到了我,問我是否有換工作的意愿,我欣然告訴他年后會(huì)考慮換工作。
期間偶爾準(zhǔn)備...時(shí)間來到2021年二月19號(hào)(今天),春節(jié)前兩天首面的字節(jié)跳動(dòng),與我談好了 offer。我在感慨字節(jié)效率時(shí),忽然想到如果還不內(nèi)推阿里,或許在入職前沒辦法面完。
于是我匆匆忙忙地聯(lián)系了東明,希望他幫我內(nèi)推簡(jiǎn)歷,并告訴他已經(jīng)拿到了字節(jié)的 offer(不算節(jié)假日就幾天時(shí)間),他非常上心并愿意幫我加急內(nèi)推,我有些感動(dòng),告訴他如果流程來得及、或則加急比較麻煩就不需要加急。
他依然幫我加急了,但我沒想到的是,這在幾個(gè)小時(shí)后會(huì)成為我無比羞愧的原因之一。
一刻鐘后,成都文檔這邊的前端負(fù)責(zé)人絕云聯(lián)系了我,詢問我什么時(shí)間方便在線筆試,我有些受寵若驚,就像是特意為我開了一個(gè)獨(dú)立的跑道,他們?yōu)橐粋€(gè)應(yīng)聘者勞心勞力。
于是我略作思索,就把筆試時(shí)間定在了今晚9點(diǎn)。
事故歷程-閱題
9點(diǎn)左右,我收到了筆試題連接,一個(gè)半小時(shí)兩道筆試題,題目如下:
/** 1. 信號(hào)燈控制器
用 React 實(shí)現(xiàn)一個(gè)信號(hào)燈(交通燈)控制器,要求:
1. 默認(rèn)情況下,
1.1. 紅燈亮20秒,并且最后5秒閃爍
1.2. 綠燈亮20秒,并且最后5秒閃爍
1.3. 黃燈亮10秒
1.4. 次序?yàn)?nbsp;紅-綠-黃-紅-綠-黃
2. 燈的個(gè)數(shù)、顏色、持續(xù)時(shí)間、閃爍時(shí)間、燈光次序都可配置,如:
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位的二進(jìn)制數(shù),為增強(qiáng)可讀性,通常我們以8位為1組進(jìn)行分割,
用十進(jìn)制來表示每一部分,并用點(diǎn)號(hào)連接,譬如 192.168.1.1。顯然,存在這樣的 IP 地址,
0到9十個(gè)數(shù)字各出現(xiàn)一次。具備這樣特征的 IP 地址里,表示成二進(jìn)制數(shù)時(shí),二進(jìn)制數(shù)左右對(duì)稱
(也就是“回文”,表示成32位二進(jìn)制不省略0)的情況有幾種,分別是哪些?要求性能盡可能高
*/
我查閱了題目,很快就發(fā)現(xiàn)了對(duì)我而言的難點(diǎn):
第一道題要使用 react ,而我?guī)缀鯖]有使用過,但我相信這并不會(huì)成為太大的阻礙,因試題并不復(fù)雜 第二道題比較晦澀,我一時(shí)沒有好的思路去解決
所以我制定好了我的答題計(jì)劃:
完成第一道題 第二道做一部分,來不及做的部分注釋思路
做題
我想首先要能跑得起來 react ,才能知道哪些語法能寫,所以我 Google 了 react ,在官網(wǎng)找到了快速起步 npx create-react-app test1。
我打開項(xiàng)目,粗略看了下結(jié)構(gòu)便快速地新建了 components/ 和 .js/.css 文件,但下一刻我就遇到了第一個(gè)預(yù)料之外的問題,初始化的項(xiàng)目使用的是 function 組件,而題目使用的卻是 class 組件,我想模仿腳手架模板寫的心思有些許受挫。

還好我記得我看過 react 使用 class 組件的視頻,我不用像無頭蒼蠅一樣去翻文檔,于是我打開慕課網(wǎng),找到了我歷史記錄中的 react 入門視頻,從中我找到了我想要的 class component 的寫法(借助 vscode 的一個(gè) react snippet 的插件),并且快速瀏覽了我之后會(huì)用到的 props 寫法。

由于初始化階段出了意外,所以我一直注意著時(shí)間,發(fā)現(xiàn)等我寫好主體結(jié)構(gòu)、props 傳參后,才過了十余分鐘,所以并沒有認(rèn)為事態(tài)有過失控。
我發(fā)現(xiàn)題目提供的數(shù)據(jù)結(jié)構(gòu)并不能保證路燈完全可配置,因?yàn)闊艄忸伾嬖谌N狀態(tài),各個(gè)燈光的時(shí)間也應(yīng)該單獨(dú)控制,所以我擴(kuò)展了 props 傳參和模擬數(shù)據(jù),并且完成了無邏輯狀態(tài)下組件的展示。
雖然有些不順利,但此時(shí)我并未感到焦急,因?yàn)橛嘞碌臅r(shí)間還有將近 70 分鐘,但接下來所發(fā)生的事就打破了我所有的預(yù)期、或則說幻想。
TS 報(bào)錯(cuò)
路燈的模擬數(shù)據(jù)要是數(shù)組,所以我拆分了組件 TrafficLight和TrafficLightItem,并且按照我記憶中我看過的 JSX 語法使用了 for 循環(huán)去生成多個(gè)TrafficLightItem,但這一步報(bào)錯(cuò)了...一個(gè) TS 的報(bào)錯(cuò),而我明明使用的是 js...

截圖為筆試后自己復(fù)現(xiàn)) 這個(gè)問題我試了很多方法:
vscode 提示 lights是any類型,我想是不是需要明確定義為 Array 才不會(huì)報(bào)錯(cuò),但 js 并不能定義類型我懷疑是否是 HMR 有問題,編輯器也胡亂報(bào)了一個(gè)錯(cuò),所以我重啟工程,在瀏覽器上仍然報(bào)錯(cuò) 我懷疑是否是 lightsprop 沒有傳遞過來,所以我直接把lights定義在當(dāng)前組件,甚至不定義變量直接使用模擬數(shù)據(jù)(一個(gè)Array)執(zhí)行map方法
最終嘗試在 return 中加一個(gè)根節(jié)點(diǎn),就不再報(bào)錯(cuò)了...

動(dòng)態(tài)修改樣式
要?jiǎng)討B(tài)切換顏色,我需要知道 react 如何動(dòng)態(tài)修改 style 樣式,我嘗試了幾種寫法,最終還是靠 Google 解決 
更新視圖
要?jiǎng)討B(tài)切換顏色,我需要知道 react 如何更新視圖,事實(shí)上我知道是通過 setState 函數(shù)。
但該函數(shù)如何調(diào)用,state 肯定又不能是普通變量,所以我又只能去 Google ,并且花了很長(zhǎng)時(shí)間去調(diào)整、嘗試 setState 應(yīng)該放到哪里去調(diào)用的問題(起初我放到 render 函數(shù)中,視圖卡住無法加載,我才意識(shí)到不能這么做)。
最終通過這篇文章[1]才解決了我的各種 this、setState、state 問題

以上種種處理完畢,時(shí)間已然沒了大半,還剩半個(gè)小時(shí)我焦急無比。
但我并沒有放棄,或許當(dāng)時(shí)的我認(rèn)為我已然能做好第一題,或許只是沒有足夠的時(shí)間做第二道題而已。
但事實(shí)往往更加殘酷,之后 10 分鐘,我寫好了三個(gè)狀態(tài)切換相關(guān)的函數(shù):閃爍函數(shù)twinkle、初始化狀態(tài)函數(shù) init 和循環(huán)進(jìn)行初始化的函數(shù) lightInterval,并處理定時(shí)器中 this 指向的問題,但我想要的路燈狀態(tài)切換并沒有出現(xiàn)。
而后 15 分鐘便是我最最煎熬的調(diào)試時(shí)間,我焦急又麻木的一次又一次的嘗試,但就是沒有解決一個(gè)問題。我的狀態(tài)切換一直沒有出現(xiàn),我知道是異步導(dǎo)致的問題,但我并不知道為什么會(huì)這樣,我的思維似乎在寫完關(guān)鍵函數(shù)后就進(jìn)入了停滯狀態(tài)...
10點(diǎn)25分,面試官提醒我準(zhǔn)備交卷,我還精神恍惚地掙扎了兩分鐘,最終在10點(diǎn)28交卷,并通過釘釘艱難地向面試官提出放棄。


代碼
以下就是一個(gè)工作將近五年,自詡功底不錯(cuò)的前端交出的試卷原樣:
/** 1. 信號(hào)燈控制器
用 React 實(shí)現(xiàn)一個(gè)信號(hào)燈(交通燈)控制器,要求:
1. 默認(rèn)情況下,
1.1. 紅燈亮20秒,并且最后5秒閃爍
1.2. 綠燈亮20秒,并且最后5秒閃爍
1.3. 黃燈亮10秒
1.4. 次序?yàn)?nbsp;紅-綠-黃-紅-綠-黃
2. 燈的個(gè)數(shù)、顏色、持續(xù)時(shí)間、閃爍時(shí)間、燈光次序都可配置,如:
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 其實(shí)很簡(jiǎn)單,塵埃落定之后很快就發(fā)現(xiàn)了問題,有兩個(gè):
我用 await去等待宏任務(wù)閃爍函數(shù)中邏輯有些混亂,定義了 cur卻沒修改他的值。
導(dǎo)致第一個(gè)問題的原因恐怕還是我寫得太少,如此離譜的、用當(dāng)朝劍去斬前朝官的事,我想不到還能找什么借口。
等歉意和客套處理妥當(dāng),事實(shí)上我也很快解決了問題——新增了一個(gè)用于實(shí)現(xiàn)異步等待的 wait 函數(shù)。

總結(jié)與感悟
決定寫這篇文章時(shí),我心中還滿是羞愧和難過。
羞愧在于走了特殊通道,但表現(xiàn)得像一個(gè)小丑,難過在于,辜負(fù)了別人的信任。
所以我想把不堪記錄下來,督促自己今后學(xué)習(xí)稍多一點(diǎn)盡量避免這樣的事故,也是想要寫出來告訴和我接觸的東明和絕云,不要因?yàn)閭€(gè)例而沮喪,請(qǐng)一如既往相信應(yīng)聘者。
正視自己的不堪,我才能變得強(qiáng)大。
額外說明:本文無意拐彎抹角碰瓷阿里,在此也保證本次換工作不會(huì)再尋求任何阿里工作機(jī)會(huì)
ssh 注:
金三銀四來了,可能部分同學(xué)會(huì)有換坑的想法,本文是一個(gè)相對(duì)反面的教材,希望能讓大家吸取一些經(jīng)驗(yàn)。
準(zhǔn)備好之前不要輕易接受面試,不要沖動(dòng),大公司面試都會(huì)留下評(píng)價(jià)記錄。
對(duì)于自己不熟悉的技術(shù)不要過分自信,可以嘗試要求面試官切換到自己熟悉的技術(shù)棧上。
— 完 —
一鍵三連「分享」、「點(diǎn)贊」和「在看」
技術(shù)干貨與你天天見~
