记一次字节跳动的面试

被猎头告知字节那边看中了我的简历,给了我面试的机会,当时既激动又紧张。一直都没收到hr的面试电话,就更紧张了,也不知道什么时候面试?什么时候才能让心里的大石头落地。后来猎头那边和我说面试邮件已经发出,准备好面试。于是迫不及待就打开邮箱看了邮件,邮件整体结构清晰流畅,措辞严谨自然,还被温馨提示面试前要做的准备--数据结构、算法、系统设计等等,一股牛逼的高科技公司的气息滚滚而来,最后结尾还不忘给飞书打一波广告。。。就这样感觉自己这两年坚持leetcode刷题终于有了用武之地,然而事情总是不顺着我们想象的方向发展!

时间很快到了7月7日,约好晚上8点面试。这天早上比之前起的更早一些,连续下了几天的雨终于停了,想想都是好兆头。于是我早早去了图书馆占了上了一个位置,好好准备面试,在网上找了关于字节面试题,笔试题基本上是考算法,因此我把所有赌注都压在算法上,整整一天都在leetcode刷算法题,希望能找回感觉,一举拿下一面。练习了一天的算法,整个人比较累了,回到家将近7点,于是在床上躺了一会儿闭目养神。

面试开始了!!!开始是毫无意外的自我介绍,然后就是一系列的提问:

  1. weex实现原理,weex的native页面是怎么和原生页面进行通信的(weex调取原生api的原理)
  2. react-redux conn 实现原理
  3. 写代码,实现洋葱模型
/**
 * 第一题:实现洋葱圈模型 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();
  1. 事件循环、宏任务与微任务
/**
 *  第二题:输出顺序
 */
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');
  1. 做过那些优化
  2. 无限滚动列表怎么实现
  3. event.target.scrollTop 是否会引起回流
  4. 给一个div,如何判断该div是否滚动到底部
  5. getBoundingClientRect()

我的提问

  1. 针对我的情况,给些学习建议
  • 面试的时候多说,不要怕说错,多和面试官沟通,把自己擅长的表现出来
  • 珍惜工作机会,在工作中多学习,搞懂弄透当前使用框架的原理,多看源码
  • 勤写博客,多总结
  • 打牢js基础
  1. 前端是否有必要搞算法,leetcode等
  • leetcode是给应届生准备的,他们没有工作经验,使用这种方式考察
  • 社招更看重工作经验,对框架原理的掌握程度,工作之余才考虑算法

最后自然是没有通过,我一直以为面试官看中的是我在leetcode学习算法,会来几道算法题,没想到面试官告诉我说觉得我写了2年的博客,更新比较勤快,所以给我面试的机会。然后就没有然后了,,,继续加油努力吧!!!

今天来解答一下上面的2道笔试题吧(最后更新于2020-7-12)

  1. 第一题:实现洋葱模型,本质上就是让我们把类似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();
  1. 第二题:这道题考察事件循环,宏任务与微任务的知识点。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
 */

参考

posted @ 2020-07-09 10:32  mingL  阅读(928)  评论(0编辑  收藏  举报