Code Monkey home page Code Monkey logo

blog's Introduction

Hi there 👋

I'm QuocVi(千鸟), a Chinese Font End Developer.

  • 🔭 I’m currently living in GuangZhou!
  • 🌱 I’m currently learning Ts.
  • 💬 My Blog: QuocVi

Languages & Tools

blog's People

Contributors

quocvi1994 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

blog's Issues

[面试真题] 富途牛牛

一面 (1.5h 一个女面试官)

面试形式为视频面试,邮件包含链接地址,网页包含代码编辑框,没有语法提示

  1. 自我介绍
  2. 在项目中担任的角色
  3. 先来个手写题吧 要求时长约15分钟
给定一系列的会议时间间隔
包括起始和结束时间 [[s1,e1][s2,e2],…[si,ei]],二维数组乱序
问题1:确定一个人是否可以参加所有会议。

我采用的思路复杂度较高

const getSort = (arr) => {
  // 根据子数组第一项做排序  返回排序后的二维数
  return arr.sort((a, b) =>  a[0] - b[0]);
}

function canJoin(arr) {
  // 0.对二维数组按照开始时间先做排序 , 然后对排序后的数组做拍平 flat
  let temp = getSort(arr);
  let tempArr = Array.flat(temp)
  
  // 1.再做数组的扁平化
  let newArr = Array.flat(arr)
  // 2.得到了一个一维的数组 但是数组内还是乱序的 
  // 所以需要重新创建一个数组 并对上述扁平化后的数组进行大小排序 在这里需要对时间做转换成时间戳
  let iArr = newArr.sort((a,b) => a - b)
  
 // 笔者在这块写的是 === 面试官指出了错误
  return tempArr == iArr
}
  1. 那我们对上述问题改改
给定一系列的会议时间间隔
包括起始和结束时间[[s1,e1][s2,e2],…[si,ei]]
问题2: 最多可以参加多少个会议

回答不符合要求

  1. 两栏布局 如何实现左边200px 右边自适应 ?

  2. 如何设计一个上传控件?

  3. 缓存有哪些?

    笔者理解成网络缓存

  4. 本地缓存讲讲?

  5. 如何用localstorge 设计一个指定时间的缓存

  6. https 的链接过程?

  7. 刚才的两道题有点复杂,那我再出一道简单的吧

给两个字符串S 和 T, 判断S能不能通过删除一些字母(包括0个)变成 T.
  1. 反问
  • 部门做什么?
    对接toc 做 很多企业的员工股权系统,以及做ipo 还有股票相关的推荐

  • 有多少部门?
    有4个前端业务中心

  • 面试多久反馈
    3-5个工作日

咨询内推的同学得知跪了,亏我还刷了一些逻辑题 (;´༎ຶД༎ຶ`)

[问题记录] 震惊w(゚Д゚)w , 千鸟做了这件事,竟差点喜提 n + 1 !!!

记一次 npm script 相关的事故

当输入npm publish的那一刻,I knew i fucked up !

定时炸弹,滴答滴答~

故事是这样开始的,让我们把时间从输入npm publish 那一刻倒退到四个月前,同样的一个下午,彼时,我在处理一个接口质量上报问题,把组内的上报 SDK 配置了 Rollup 打包,并设置了 umd 格式输出,整完上报配置后,顺手摸索玩了下 rollup 配置,并没有留意到我把输出格式改成了 es 并 commit 到仓库,后来这个代码被publish 到了内网,因为用的业务只有一个,所以,隐患也就这样埋下。

爆发

直到一天前的下午,组长使用这个 SDK 的时候,发现这个上报 SDK 无法使用,反馈给另一位同事,他定位后发现这个问题,看到commit 记录来自我,便让我重新发布到内网。我改了下版本还有输出格式后,便想也没想,输入了 npm publish。

命令行飞速的打印上传日志,而那一刻,我也意识到,我搞砸了,把内网包发到了外网。因为我的 npm 源为官方源,而非公司内网源,我也没有在本地配置 nrm。所以很快的,这个内网包被发布了出去。

挽救

于是立刻查了下如何取消一个 npm 包发布,快速的复制粘贴输入 npm unpublish --force

但是,控制台竟输出了

截屏2021-03-27 下午8 43 28

一查才知道,原来 npm 发布策略是 发布后 24后内可以撤回,但是,但是,前提是这个包没有被其他包依赖

不凑巧的是,这个包恰好被同项目组的另一个包,在package json 引用,盲猜是内网npm 源同名包。这也导致,我执行 npm unpublish 报了错误。

但是这样的话,引出来两个问题??

被依赖的包 执行 npm unpublish 真的什么都没有发生吗?

我们在 npm 直接搜索 这个包

截屏2021-03-27 下午10 27 57

发现无法搜索,但是如果我们直接在url 拼接该包名地址呢?

截屏2021-03-27 下午10 31 56

发现该包仍可通过这种方式访问,并且当我们在项目中执行 npm i 安装这个包的时候仍能安装,于是有个比较明晰的答案就是:

npm 官方在一个包被其他包依赖的时候,并不希望你执行 unpublish 撤回操作,但是若你强制执行 --force ,它将无法正常搜索,但是你仍然可以在自己的发布包列表和在地址栏拼接地址的方式访问这个包。

怎么样才能真正彻底的删除一个npm 包?

先说答案,你需要在引用这个包的npm 包,删除引用,并重新发布新版本,这样你再执行一次命令,您就能正常删除这个包。

截屏2021-03-27 下午8 44 16

这时,再通过url 访问该包,就发现无法找到该包。

最糟糕的方式

世上事往往事与愿违,我们也没有 npm unpublish --force 这么好用的方式, 如果真的无法撤回,比如依赖包已经废弃,权限不在自己手中,或者是超过24小时。

那么,我们只能采用最次的方式解决问题。

笨拙的错误,用拙劣的手段去解决

您还可以,疯狂的发新版本空包,掩盖旧版本记录,或者发布干扰信息的新包,掩盖这个错误。

最后

发包前请三思!!! 最好配置 nrm ! ! !

[面试真题] 荔枝FM

笔试

  1. 请写出 script ,script async ,script defer 区别?

2.请写出 css 隐藏页面元素的三种方式?

3.题2提到的三种方式有何不同?

4.一个promise settimeout的题

5.cors 预检请求 preflight request作用是什么?

6.cookie 的 httponly 作用是什么?

7.请用js 实现防抖函数

一面

基础

1.script defer ansync 什么时候用?
2.link 场景 与 script 区别, link 除了css 还有什么?
3.meta 标签属性有哪些?
4.语义化做法
5.eslint 流程
6.display 几个样式使用场景和原因
7.布局几种? 最长使用?
8.文本益处失效有无遇到?felx-item问题 没遇到
9.xcode inspect 流程
10.布局移动端
11.rem 精度丢失

js

12.evenloop
13.node eventop 区别? 不了解
14.async promise 区别
15.promise 怎么做全局异常补货?sentry机制
16.let const var 块级作用域
17.闭包
18.gc 垃圾回收
19.apply call bind 区别
20.如何实现apply
21.bind 如何实现立即执行的
22.new 的具体流程步骤
23.跨域
24.jsonp 流程 与 jsbirdge 类似
25.csp 安全设置
26.用户系统升级 浏览器版本升级导致的问题 cookie same-site
27.cookie httponly 设置
28.xss csrf 理解,如何避免?线上有无遇到?讲到如何避免被劫持和被路由截包
29.防抖节流 理解 和场景

网络协议 浏览器

1.csp ajax header 🈶️哪些看重的 状态吗 content-type http版本 gzip br压缩等
2.http 1.x http2.0 区别?
3.http 1.x keep-alive 与 多路复用 比较?
多路服用 二进制分针 使用
4.http2 并发丢包会怎么样?重传 组装 按照自己等理解
5.chrome 地址栏目 输入url 流程?
6.在上述链路优化 dns配置 cdn 缓存 预动画 骨架屏等 顺便提到了 监控相关
7.监控方面做的事情,优化的数据? 还有哪些?

技术栈

1.react function class hook 区别 和场景?
2.fiber?
3.使用中自己遇到的哪些框架问题?活动模版 状态更新问题
4.vue keep-alive 如何通过react 实现 context redux react router

项目

1.uc 小游戏做了哪些事情? 有无做过游戏项目?
2.印象深刻的项目? 业务复杂的 技术提升块的 从头到尾完整的工程的
3.有遇到什么棘手的问题?怎么解决定位?
4.工程化 有没有赋能团队的事情?动画方案
5.有没有做过工作之外帮助团队的事情? ui 共享协同云盘搭建

拓展

1.平时有没有搭建服务器玩玩?
2.对外有无输出 写博客什么的?
3.怎么学习?
4.未来三年的定位规划?

还有什么要问的?

1.项目的技术栈
2.未来的工作内容

[知识沉淀] 从输入URL到页面展示,这中间发生了什么?

如果有 n 场面试,那至少有 n +1 次,会提到这个问题?可谓是老八股文了,但是你真的懂吗?

以下我们采用李兵的浏览器工作原理与实践还有其他资料,去讲解,这个过程中到底会有哪些流程。


首先,我们不废话,直接给出标准的面试回答的模版流程,然后我们再娓娓道来。

  1. 导航栏用户输入

    • 用户在地址栏按下回车,浏览器进程 检查输入(关键字 or 符合 URL 规则),若是URL 组装协议,构成完整的url
    • 回车前,当前页面会执行 onbeforeunload 事件
    • 浏览器进入加载状态,左上角有小球转
  2. URL 请求

    • 浏览器进程 通过进程间通信 (IPC) 把url请求发送到 网络进程

    • 网络进程 接收到url请求后检查本地缓存是否缓存了该请求资源,如果有则将该资源返回给浏览器进程

    • 如果没有,网络进程向web服务器发起http请求(网络请求),请求流程如下

      1. 进行DNS解析,获取服务器ip地址,端口,DNS查询顺序如下 (在这一步可以执行的优化手段 dns-prefetch)

        • 浏览器自身DNS
        • 操作系统DNS
        • 本地hosts文件
        • 向域名服务器发送请求
      2. 利用ip地址和服务器建立tcp连接(三次握手🤝, 五层因特网协议栈)

      3. 构建请求头信息 header

      4. 发送请求头信息

      5. 服务器响应后,网络进程接收响应头和响应信息,并解析响应内容

  3. 网络进程解析响应流程

    • 检查状态码,如果是301/302,则需要重定向,从Location自动中读取地址,重新上一步,如果是200,则继续处理请求。
    • 200响应处理,检查响应类型Content-Type,如果是字节流类型,则将该请求提交给下载管理器,该导航流程结束,不再进行
    • 后续的渲染,如果是html则通知浏览器进程准备渲染进程准备进行渲染。(下载文件、加载资源、渲染 HTML)
  4. 准备渲染进程

    • 浏览器进程检查当前url是否和之前打开的渲染进程根域名是否相同,如果相同,则复用原来的进程,如果不同,则开启新的渲染进程

5.传输数据、更新状态

  • 渲染进程 准备好之后,浏览器会向 渲染进程 发起“提交文档”的消息,渲染进程接收到消息和网络进程建立传输数据的“管道”
  • 渲染进程接收完数据后,向浏览器发送“确认提交”
  • 浏览器进程接收到确认消息后更新浏览器界面状态:移除旧文档、更新界面、地址栏,导航历史、安全提示状态等。
  • 此时标识浏览器加载状态的小圆圈,从此前 URL 网络请求时的逆时针选择,即将变成顺时针旋转(进入渲染阶段)

6.渲染流水线

  • 构建 DOM 树

    1. 输入:HTML 文档
    2. 处理:HTML 解析器解析
    3. 输出:DOM 数据解构
  • 样式计算

    1. 输入:CSS 文本
    2. 处理:属性值标准化,每个节点具体样式(继承、层叠)
    3. 输出:styleSheets(注意 官方文档没有这种说法 CSSOM)
  • 布局(DOM 树中元素的计划位置)

    1. DOM & styleSheets 合并成渲染树
    2. 布局树(DOM 树中的可见元素)
    3. 布局计算。
  • 分层

    1. 特定节点生成专用图层,生成一棵图层树(层叠上下文、Clip,类似 PhotoShop 里的图层)
    2. 拥有层叠上下文属性(明确定位属性、透明属性、CSS 滤镜、z-index 等)的元素会创建单独图层
    3. 没有图层的 DOM 节点属于父节点图层
    4. 需要剪裁的地方也会创建图层
  • 绘制指令

    1. 输入:图层树
    2. 渲染引擎对图层树中每个图层进行绘制
    3. 拆分成绘制指令,生成绘制列表,提交到合成线程
    4. 输出:绘制列表
  • 分块

    1. 合成线程会将较大、较长的图层(一屏显示不完,大部分不在视口内)划分为图块(tile, 256256, 512512)
  • 光栅化(栅格化)

    1. 在光栅化线程池中,将视口附近的图块优先生成位图(栅格化执行该操作)
    2. 快速栅格化:GPU 加速,生成位图(GPU 进程)
  • 合成绘制

    1. 绘制图块命令——DrawQuad,提交给浏览器进程;
    2. 浏览器进程的 viz 组件,根据DrawQuad命令,绘制在屏幕上。

[知识沉淀] 观察者模式 or 订阅发布 ??

发布订阅

export default {
  events: {},
  on (event: any, fn: any) {
    const events = this.events;

    if (!events[event]) {
      events[event] = [fn]
    } else {
      events[event].push(fn)
    }
  },
  emit() {
    const args = [].slice.call(arguments, 0);
    const event = args[0];
    const callArgs = args.slice(1)

    const queue = this.events[event];
    if (queue) {
      queue.forEach(fn => {
        fn.apply(null, callArgs)
      });
    }
  }
}

[手写源码] 给我一个 Promise 好吗?

Promise 作为 ES6 新出的异步内置对象,基本是必考的知识点,也是我们非常常用的一个异步操作方法;

在解决回调嵌套方便非常的好用,此外,由于采用了微任务,提高了代码执行效率,微任务是由 js 引擎提供;通常我们所指的 promise 为 Promise A+ 规范,它包含以下规则:


[手写源码] 防防防防防抖 & 节 ~~~~~流

看到标题,咱们先说概念

  1. 防抖 任务频繁发生的情况下,只有任务时间超过指定间隔,才会执行任务
    实现:事件触发的时候,清除掉之前的timeout,声明一个新的timeout
function debounce(fn, wait) {
    let timer = null
    return function(...args) {
        if (timer){ clearTimeout(timer)}

        timer = setTimeout(() => {
            fn.apply(this, args)
        }, wait);
    }
}
  1. 节流 指定间隔时间内只执行一次任务
    实现:如果时间间隔大于指定时间,则执行任务,否则清除掉
function throttle(fn, wait) {
    let canRun = true
    return function () {
        if (!canRun) return;
        canRun = false;
        setTimeout((...args) => {
            fn.apply(this, args)
            canRun = true
        }, wait);
    }
}

[手写算法] 斐波那契数

斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给你 n ,请计算 F(n) 。

此题有很多方式去解决,动态规划、递归等;

面试遇到这个问题,面试官人真好,太简单了,上来当然是一把梭:

const fib = (n) => {
  if (n === 0) return 0;
  if (n < 3) return 1;
 return fib(n - 1) + fib(n - 2);
}

然后就跪了,时间复杂度超时 Σ( ° △ °|||)︴

让我们重新屡屡,在这里,我们用到了递归的方式,假设输入的n = 100;

那么,当我们执行的时候就有

100 = 99 + 98
99 = 98 + 97
98 = 97 + 96
.......

可以看到,在这个递归过程中会存在很多重复的值计算,这也是导致复杂度高的根本原因,那么怎么解决呢?很简单,我们把值存起来。

所以,就有一种更为优雅的解法:

const fib = (n, map = {}) => {
  if (n === 0) {
     map[n] = 0;
     return 0;
  };
  if (n < 3) { 
    map[n] = 1;
    return 1;
  };
  if (!map[n]) {
    return fib(n-1, map) + fib(n-2, map)
  }
}

如此就有递归版本的斐波解法

[手写源码] 函数变变变~ curry 化 !!!

写法一

function  curry(func) {
    return function curried (...args) {
        if (args.length >= func.length) {
            return func.apply(this, args)
        } else {
            return function (...args2) {
                return curried.apply(this, args.concat(args2))
            }
        }
    }
}

写法二

简单粗暴版本

const curry = (fn) =>
(
  temp = (...args) =>
    args.length === fn.length
     ? fn(...args)
     : (...arg) => temp(...arg, ...args)
)

[手写源码] 多种姿势实现数组map

reduce 实现 map

Array.prototype._map = function(fn, callbackThis) {

    let res = []
    let cbthis = callbackThis || null

    this.reduce((before, after, idx, arr) => {
        res.push(fn.call(cbthis, after, idx ,arr))
    }, null)

    return res;
}

[知识总结] 让我们聊聊 302 状态码与劫持

当我们去讨论一个东西的时候,我们首先需要去了解它是什么,让我们看看 MDN 对它的解释

HTTP 302 Found 重定向状态码表明请求的资源被暂时的移动到了由Location 头部指定的 URL 上。浏览器会重定向到这个URL, 但是搜索引擎不会对该资源的链接进行更新 (In SEO-speak, it is said that the link-juice is not sent to the new URL)。

即使规范要求浏览器在重定向时保证请求方法和请求主体不变,但并不是所有的用户代理都会遵循这一点,你依然可以看到有缺陷的软件的存在。所以推荐仅在响应 GET 或 HEAD 方法时采用 302 状态码,而在其他时候使用 307 Temporary Redirect 来替代,因为在这些场景下方法变换是明确禁止的。

在确实需要将重定向请求的方法转换为 GET的场景下,可以使用 303 See Other。例如在使用 PUT 方法进行文件上传操作时,需要返回确认信息(例如“你已经成功上传了xyz”)而不是上传的资源本身,就可以使用这个状态码。

[手写代码] 一个 LazyMan 是怎么养成的?

编程题,实现LazyMan:

• LazyMan('Hank')

  • Hi! This is Hank!

• LazyMan('Hank').sleep(10).eat('dinner')

  • Hi! This is Hank!
  • 等待10秒
  • Wake up after 10
  • Eat dinner~

• LazyMan('Hank').eat('dinner').eat('supper')

  • Hi This is Hank!
  • Eat dinner~
  • Eat supper~

• LazyMan('Hank').sleepFirst(5).eat('supper')

  • 等待5秒
  • Wake up after 5
  • Hi This is Hank!
  • Eat supper

• 每个函数都返回this,供链式调用。
• this里面建立一个调用队列,在执行LazyMan时立即setTimeout(()=>顺序执行调用栈内容),确保链式调用完之后会开始执行调用栈内容。
• 根据函数的优先级去放入调用队列的前面或后面,如sleepFirst在前,sleep在后。
• 顺序执行调用栈时可被阻塞,如sleepFirst的函数执行后会返回一个Promise,然后调用栈发现是Promise则进行await,等待resolve之后才执行下一个函数。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.