被獵頭告知字節那邊看中了我的簡歷,給了我面試的機會,當時既激動又緊張。一直都沒收到hr的面試電話,就更緊張了,也不知道什么時候面試?什么時候才能讓心里的大石頭落地。后來獵頭那邊和我說面試郵件已經發出,准備好面試。於是迫不及待就打開郵箱看了郵件,郵件整體結構清晰流暢,措辭嚴謹自然,還被溫馨提示面試前要做的准備--數據結構、算法、系統設計等等,一股牛逼的高科技公司的氣息滾滾而來,最后結尾還不忘給飛書打一波廣告。。。就這樣感覺自己這兩年堅持leetcode刷題終於有了用武之地,然而事情總是不順着我們想象的方向發展!
時間很快到了7月7日,約好晚上8點面試。這天早上比之前起的更早一些,連續下了幾天的雨終於停了,想想都是好兆頭。於是我早早去了圖書館占了上了一個位置,好好准備面試,在網上找了關於字節面試題,筆試題基本上是考算法,因此我把所有賭注都壓在算法上,整整一天都在leetcode刷算法題,希望能找回感覺,一舉拿下一面。練習了一天的算法,整個人比較累了,回到家將近7點,於是在床上躺了一會兒閉目養神。
面試開始了!!!開始是毫無意外的自我介紹,然后就是一系列的提問:
- weex實現原理,weex的native頁面是怎么和原生頁面進行通信的(weex調取原生api的原理)
- react-redux conn 實現原理
- 寫代碼,實現洋蔥模型
/**
* 第一題:實現洋蔥圈模型 compose
*/
const app = { middlewares: [] };
app.use = (fn) => {
app.middlewares.push(fn);
};
app.compose = function() {
// Your code goes here
}
app.use(next => {
console.log(1);
next();
console.log(2);
});
app.use(next => {
console.log(3);
next();
console.log(4);
});
app.use(next => {
console.log(5);
next();
console.log(6);
});
app.compose();
- 事件循環、宏任務與微任務
/**
* 第二題:輸出順序
*/
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
- 做過那些優化
- 無限滾動列表怎么實現
- event.target.scrollTop 是否會引起回流
- 給一個div,如何判斷該div是否滾動到底部
- getBoundingClientRect()
我的提問
- 針對我的情況,給些學習建議
- 面試的時候多說,不要怕說錯,多和面試官溝通,把自己擅長的表現出來
- 珍惜工作機會,在工作中多學習,搞懂弄透當前使用框架的原理,多看源碼
- 勤寫博客,多總結
- 打牢js基礎
- 前端是否有必要搞算法,leetcode等
- leetcode是給應屆生准備的,他們沒有工作經驗,使用這種方式考察
- 社招更看重工作經驗,對框架原理的掌握程度,工作之余才考慮算法
最后自然是沒有通過,我一直以為面試官看中的是我在leetcode學習算法,會來幾道算法題,沒想到面試官告訴我說覺得我寫了2年的博客,更新比較勤快,所以給我面試的機會。然后就沒有然后了,,,繼續加油努力吧!!!
今天來解答一下上面的2道筆試題吧(最后更新於2020-7-12)
- 第一題:實現洋蔥模型,本質上就是讓我們把類似fn1(),fn2(),fn3()...轉化成fn1(fn2(fn3(...)))這種結構執行,我們可以使用遞歸調用完成結構轉變(當然也可以使用循環實現),代碼如下:
const app = { middlewares: [] };
app.use = (fn) => {
app.middlewares.push(fn);
};
app.compose = function() {
// Your code goes here
function dispatch(index){
if(index===app.middlewares.length) return ;
const fn=app.middlewares[index];
return fn(()=>dispatch(index+1))
}
dispatch(0);
}
app.use(next => {
console.log(1);
next();
console.log(2);
});
app.use(next => {
console.log(3);
next();
console.log(4);
});
app.use(next => {
console.log(5);
next();
console.log(6);
});
app.compose();
- 第二題:這道題考察事件循環,宏任務與微任務的知識點。setTimeout這些計時器屬於宏任務會優先執行,promise...then屬於微任務執行優先級比宏任務低,會在宏任務執行完成之后執行。特別注意的是promise回調函數里面的執行代碼屬於宏任務,then、catch或者finally回調函數才屬於微任務,所以執行順序為
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
//執行順序為:
/**
* script start
* async1 start
* async2
* promise1
* script end
* async1 end
* promise2
* setTimeout
*/