【面试】阿里一面总结

192 阅读8分钟

题目

  1. 浏览器点击300ms延时是因为什么?现在还有吗?怎么解决的?点击穿透

  2. node的事件循环和浏览器事件循环区别?

一张图带你搞懂Node事件循环

深入理解NodeJS事件循环机制

Node.js标准课程:3.事件循环

image.png

  • event loop:检查是否有异步IO或者计时器,有的话进入事件循环

  • 事件循环:六个阶段,一圈代表一次轮询,一个tick

    • timers:计时器(setTimeout、setInterval的回调函数),如果定时器到时间了,则会被调用执行。

    • pending callback: 执行某些系统操作的回调,例如TCP错误类型

    • idle prepare:系统内部使用

    • poll:轮询阶段,执行与IO相关的几乎任何回调(除去定时器和setImmediate的回调),例如文件读取,http请求

      • 如果队列有回调函数,依次执行回调
      • 如果没有,则阻塞在这里,直到有新的回调出现
        • 如果这时候有poll出现新的回调,则立即执行。
        • 如果check队列有setImmediate回调,则继续向下走check队列
        • 如果有设定的timers,并且timers时间到达了,则event loop将绕回timers阶段执行timers
        • 如果同时有setImmediate和setTimeout,则从按照顺序poll->check->timeout依次执行
    • check:setImmediate的回调,这个回调是直接进入到这个队列中的

    • close callbacks:一些关闭的回调函数 socket.on('close');

  • 经过分析发现,基本会阻塞在poll阶段等待执行,但如果有setImmediate或者setTimeout则会停止等待,继续走流程。

nodejs事件循环.png

  • 微任务:
    • 不属于事件循环,执行时机是每执行一个宏任务前都会检查微任务队列是否有微任务,有的话执行,这一点跟浏览器事件循环还比较一致,而且如果微任务执行过程中插入新的微任务,是会在本次微任务队列中直接执行,而不是等到下一次循环。
    • nextTick优先级大于promise优先级
  • 和浏览器事件循环
    • 不同点
      • 浏览器就是一个微任务队列和一个宏任务队列
      • 宏任务队列没有分出来那么多过程,而是一个队列
    • 相同点:
      • 执行一个宏任务前将微任务的所有回调先执行完,nodejs不会等完整的tick而是一个宏任务之后就检查微任务。
  1. cookie和sesstionId区别,单点登录的区别,前端方面实现从A网站到B网站,如何不重新登录?前端做了哪些事情?

缺点:

  1. csrf(跨站请求伪造)
    • http referer
    • 随机token
  2. 分布式session(增加一个单独的redies服务器)

JWT登录方案?

  1. 和cookie-session区别?cookie-session需要服务端存储。JWT是后端生成token,可以解析出来用户名。
  2. 缺点
    • token安全性,token窃取,能被解析出来,需要搭配https

    • 性能

    • 失效时间:redis失效时间存在token里

    • 单点登录镇楼图

image.png

  1. ts中let、const实现的区别?
  • 使用 let 声明的变量是只需要推导至这个值从属的类型即可
  • 而 const 声明的原始类型变量直接一步到位收窄到最精确的字面量类型,但对象类型变量仍可变(但同样会要求其属性值类型保持一致)。

image.png

let被推断为string

image.png const直接被推断为精确的字面量类型,但是如下如果是一个const对象,因为属性还是可以被修改的,所以还是被推断为string类型

image.png

  1. 网络五层模型,http1 2 3区别

  2. 技术选型思路?

  3. 事件捕获和冒泡的区别?有没有哪些事件是不支持冒泡的?

    • 分别是微软和网景提出的两种事件模型,捕获是从外到里,冒泡是从里到外,addEventListener第三个参数useCapture可以改变事件执行时机。默认是false,冒泡阶段执行,true的话改为捕获阶段执行。
    • 阻止冒泡有2种方式:
      • e.stopPropagation:阻止了事件往上冒泡,但不阻止事件本身(默认事件)
      • 返回false:不仅阻止了事件往上冒泡,而且阻止了事件本身(默认事件)
    • 不支持冒泡的事件
      • scroll 事件
        • scroll 事件不会冒泡,这个带来的影响就是,当我们去做事件委托的时候,其它的大部分事件可以在冒泡阶段的时候完成委托,而 scroll 事件必须在捕获阶段完成委托。
        • scroll 事件无法取消( 没有冒泡的基本都没法取消 ),scroll 回调中的 preventDefault 和 stopPropagation 都是无效的。
      • focus、blue事件:也是无法冒泡,无法取消的
      • Media 事件:由媒介(比如视频、图像和音频)触发的事件,都不冒泡,简单举例:
        • onpause 当媒介被用户或程序暂停时运行的脚本
        • onplay 当媒介已就绪可以开始播放时运行的脚本
        • onplaying 当媒介已开始播放时运行的脚本
        • onsuspend 在媒介数据完全加载之前不论何种原因终止取回媒介数据时运行
      • mouseleave 和 mouseenter:同样不会冒泡,当这种不冒泡的特性发生在鼠标事件的时候,显得额外的符合直觉
    • 你真的理解 事件冒泡 和 事件捕获 吗?
    • JavaScript 中那些不会冒泡的事件
  4. 0.1 + 0.2 不等于 0.3的原因?

    后端问为什么前端数值精度会丢失? 解决方法:

    1. 转换为整数
    2. 使用BigInt
  5. promise 坑人题,😄,终究还是答错了

new Promise((res,rej)=>{
   console.log(1);
   res(2);
   console.log(3)
   throw Error('abc')
}).catch((err)=>{
   console.log('123')
}).then((res)=>{
   console.log(res)
})

console.log('333')

可以看看上面题的输出顺序是什么?这里有个坑,resolve后再throw还会reject吗?就是被这个点给迷惑住了,我在想executor执行的时候是捕获了异常的,所以肯定是走到了reject中,但是,reject执行的时候是会判断当前promise的状态是不是pending,如果是pending才会变化,否则是不会执行的。

1 3 33 2

解答:

来吧,上规范,promisesaplus.com/, 还是说人话,直接中文吧。 【译】 Promises/A+ 规范

image.png

这道题还是答错了,之前以为promise掌握的不错了,一做题还是崩啊,所以这知识真是越学发现自己不会的越多。

  1. ts补充以下泛型
function a(o,key) {
    return o[key]
}
  1. vue中v-if v-show区别
  2. vue中computed与watched区别

编程题

  1. 给一个多维数组,先展开成一维数组,再去重,再排序,如果自己写出排序加分
function flatten(arr, depth = Infinity) {
    return arr.reduce((acc, cur) => {
        return acc.concat(Array.isArray(cur) && depth > 0 ? flatten(cur, depth - 1) : [cur])
    }, []);
}
// 排序写了快排
function quickSort(arr) {
    if (!arr.length) {
        return [];
    }
    const len = arr.length;
    // 随机选取一个枢纽元,放到最后一个位置
    const pivotIndex = Math.round(Math.random() * (len - 1));
    const pivot = arr[pivotIndex];
    swap(arr, pivotIndex, len - 1);

    const left = [];
    const right = [];
    for (let i = 0; i < len - 1; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    return [...quickSort(left), pivot, ...quickSort(right)]
}
  1. 写一个深克隆,考虑函数和null
function deepCopy(obj) {
    const map = new Map();
    const clone = (obj) => {
        if (!obj || typeof obj !== 'object') {
            return;
        }
        if (map.has(obj)) {
            return map.get(obj);
        }
        let result = Array.isArray(obj) ? [] : {};
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                const val = obj[key];
                if (typeof val === 'object') {
                    result[key] = deepCopy(val);
                } else {
                    result[key] = obj[key];
                }
            }
        }
        map.set(obj, result);
        return result;
    }
    return clone(obj);
}

其他

  1. vue中keep-alive组件原理?

    • 本质是把组件移动到隐藏的容器中,触发deActivate api,而激活是把组件从隐藏容器中搬运回原来的容器,触发active事件
    • 组件的状态不变
    • 多出来deactivated和actived生命周期,beforeDestory和destoryed不会再被触发,因为不会被真正的销毁。
  2. vue中teleport组件:用来将组件dom移动到指定的位置,通常用于modal,实现就是渲染时将其挂载到to的下面。

  3. eslint

    • npm init @eslint/config : 创建规则文件
    • npx mrm lint-staged:安装提交hooks 钩子,执行eslint命令

总结

  1. 如果是常见面试题的,自己掌握的回答的就比较好
  2. 我觉得日常看技术文章的分别就区分出来了,有些确实是跟你之前很多年的积累有关,即使突击,它也是能面出来的,所以以后要养成看技术文章的习惯
  3. 很多知识点是你认为你懂了,其实一问又被难住了,其实没有真正掌握,所以学习的方法还是得总结才能内化成自己的知识,否则非常容易忘记。没有真正理解的知识点过段时间就会忘,即使你当时懂了,如果长时间不用,也是会忘的。学习还是需要总结+实践才行。