1.TCP的拥塞控制

如若一点概念没有,建议看视频https://www.bilibili.com/video/BV1L4411a7RN?from=search&seid=2760293777115252799

主要想法:从丢包情况估计网络的负载情况,调整发送速率,防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。

因特网建议标准RFC2581定义了进行拥塞控制的四种算法,即慢开始/慢启动(Slow-start),拥塞避免(Congestion Avoidance)快重传(Fast Restrangsmit)和快回复(Fast Recovery)。我们假定

  1. 数据是单方向传送,而另外一个方向只传送确认

  2. 接收方总是有足够大的缓存空间,因为发送窗口的大小由网络的拥塞程度来决定。

慢开始

(立下flag)每日10道前端面试题-04

  1. 在主机刚刚开始发送报文段时可先将拥塞窗口 cwnd 设置为一个最大报文段 MSS 的数值。

  2. 在每收到一个对新的报文段的确认后,将拥塞窗口增加至多一个 MSS 的数值(一开始窗口大小为1,发送一个,接收一个,增长为2;发送两个,得到两个确认,增长为4......因此,窗口是指数增长的)。

  3. 用这样的方法逐步增大发送端的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。

  4. 因为拥塞窗口是指数增长的,为防止后期增长过快,需要另外一个变量---慢开始门限(阈值)ssthres,当cwind == ssthress时,要预防拥塞的产生,开始执行拥塞避免算法,cwnd按线性规律增长

  5. 当网络发生拥塞(即没有在TTL时间内接收到确认数据报,确认超时),把ssthresh值更新为拥塞前cwind值的一半,cwnd重新设置为1,按照步骤2执行。

快重传

发送端只要一连收到三个重复的 ACK 即可断定有分组丢失了,就应立即重传丢失的报文段而不必继续等待为该报文段设置的重传计时器的超时。

快恢复

算法有以下两个要点:

  1. 当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把慢开始门限减半,这是为了预防网络发生拥塞(同慢启动)。

  2. 由于发送方现在认为网络很可能没有发生拥塞,因此现在不执行慢开始算法,而是把cwnd值设置为慢开始门限减半后的值(而不是同慢启动一样从1开始),然后开始执行拥塞避免算法,是拥塞窗口的线性增大。

(立下flag)每日10道前端面试题-04

2、算法——扑克牌问题(字节跳动)

描述

我手中有一堆扑克牌, 但是观众不知道它的顺序。
第一步, 我从牌顶拿出一张牌, 放到桌子上。
第二步, 我从牌顶再拿一张牌, 放在手上牌的底部。
第三步, 重复第一步、第二步的操作, 直到我手中所有的牌都放到了桌子上。
最后, 观众可以看到桌子上牌的顺序是:(牌底部)1,2,3,4,5,6,7,8,9,10,11,12,13(牌顶部)
请问, 我刚开始拿在手里的牌的顺序是什么?
请编程实现。

算法解读

 这个题的核心点在于:      

            我从牌顶拿出一张牌, 放到桌子上。

            我从牌顶再拿一张牌, 放在手上牌的底部。

           重复。

使用逆向思维:

           从手上最底部拿出一张牌放在最顶部。

          从桌子上最顶部拿出一张牌放在手上最顶部。

          重复。
————————————————

解析

(立下flag)每日10道前端面试题-04

3.串行,并行和并发的区别

 注意:串行,并行和并发是针对线程而言

  • 串行:和进程中的同步类似,都是只有一个操作执行完成后,才会进行下一个操作,否则一直处于等待状态

  • 并行处理:指的是同一时间段可以同时处理多个线程,重点是要同时,即需要多个CPU处理器

  • 并发处理:指在同一个时间段多个程序都可以处于开始运行和运行完毕之间的状态,不一定要同时

4.js将图片转化为base64

(立下flag)每日10道前端面试题-04

5.浏览器如何预览图片,假设我要上传图片,未上传前我想在浏览器看到我待上传的图片

(立下flag)每日10道前端面试题-04

6.[前端基础]编写一个自定义事件类,包含on/off/emit/once方法

(立下flag)每日10道前端面试题-04

7. doctype的作用是什么?

声明文档类型,告知浏览器用什么文档标准解析这个文档:

  • 怪异模式:浏览器使用自己的模式解析文档,不加doctype时默认为怪异模式

  • 标准模式:浏览器以W3C的标准解析文档

8. 手写call()

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数
语法:function.call(thisArg, arg1, arg2, ...)

call()的原理比较简单,由于函数的this指向它的直接调用者,我们变更调用者即完成this指向的变更:

(立下flag)每日10道前端面试题-04

基于以上原理, 我们两句代码就能实现call()

(立下flag)每日10道前端面试题-04

但是我们有一些细节需要处理:

(立下flag)每日10道前端面试题-04

9. 手写apply()

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
语法:func.apply(thisArg, [argsArray])

apply()call()类似,区别在于call()接收参数列表,而apply()接收一个参数数组,所以我们在call()的实现上简单改一下入参形式即可

(立下flag)每日10道前端面试题-04

10. 手写bind()

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
语法: function.bind(thisArg, arg1, arg2, ...)

从用法上看,似乎给call/apply包一层function就实现了bind():

(立下flag)每日10道前端面试题-04

但我们忽略了三点:

  1. bind()除了this还接收其他参数,bind()返回的函数也接收参数,这两部分的参数都要传给返回的函数

  2. new的优先级:如果bind绑定后的函数被new了,那么此时this指向就发生改变。此时的this就是当前函数的实例

  3. 没有保留原函数在原型链上的属性和方法

    (立下flag)每日10道前端面试题-04

(立下flag)每日10道前端面试题-04

相关文章: