爱学习的小伙子

爱学习的小伙子 查看完整档案

长沙编辑中南大学  |  计算机 编辑  |  填写所在公司/组织 www.daoxinlu.com 编辑
编辑

初入前端的小白

个人动态

爱学习的小伙子 赞了文章 · 8月12日

为什么我们要熟悉这些通信协议? 【精读】

打个广告,欢迎加入我们的前端开发交流群:

  • 微信群:

clipboard.png

  • QQ群

clipboard.png

前端的最重要的基础知识点是什么?

  • 原生javaScriptHTML,CSS.
  • Dom操作
  • EventLoop和渲染机制
  • 各类工程化的工具原理以及使用,根据需求定制编写插件和包。(webpack的plugin和babel的预设包)
  • 数据结构和算法(特别是IM以及超大型高并发网站应用等,例如B站
  • 最后便是通信协议
在使用某个技术的时候,一定要去追寻原理和底层的实现,长此以往坚持,只要自身底层的基础扎实,无论技术怎么变化,学习起来都不会太累,总的来说就是拒绝5分钟技术

从输入一个url地址,到显示页面发生了什么出发:

  • 1.浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
  • 2.建立TCP连接(三次握手);
  • 3.浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
  • 4.服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
  • 5.浏览器将该 html 文本并显示内容;
  • 6.释放 TCP连接(四次挥手);

目前常见的通信协议都是建立在TCP链接之上

那么什么是TCP

TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答

TCP三次握手的过程如下:
  • 客户端发送SYN报文给服务器端,进入SYN_SEND状态。
  • 服务器端收到SYN报文,回应一个SYN(SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。
  • 客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。
  • 三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了。
如图所示:

clipboard.png

TCP的四次挥手:
  • 建立一个连接需要三次握手,而终止一个连接要经过四次握手,这是由TCP的半关闭(half-close)造成的。具体过程如下图所示。
  • 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。
  • 接收到这个FIN的对端执行 “被动关闭”(passive close),这个FIN由TCP确认。

注意:FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。

  • 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。
  • 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。 [3]

既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。

特别提示: SYN报文用来通知,FIN报文是用来同步的

clipboard.png

以上就是面试官常问的三次握手,四次挥手,但是这不仅仅面试题,上面仅仅答到了一点皮毛,学习这些是为了让我们后续方便了解他的优缺点。

TCP连接建立后,我们可以有多种协议的方式通信交换数据:

最古老的方式一:http 1.0

  • 早先1.0的HTTP版本,是一种无状态、无连接的应用层协议。
  • HTTP1.0规定浏览器和服务器保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器处理完成后立即断开TCP连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)。
  • 这种无状态性可以借助cookie/session机制来做身份认证和状态记录。而下面两个问题就比较麻烦了。
  • 首先,无连接的特性导致最大的性能缺陷就是无法复用连接。每次发送请求的时候,都需要进行一次TCP的连接,而TCP的连接释放过程又是比较费事的。这种无连接的特性会使得网络的利用率非常低。
  • 其次就是队头阻塞(headoflineblocking)。由于HTTP1.0规定下一个请求必须在前一个请求响应到达之前才能发送。假设前一个请求响应一直不到达,那么下一个请求就不发送,同样的后面的请求也给阻塞了。
Http 1.0的致命缺点,就是无法复用TCP连接和并行发送请求,这样每次一个请求都需要三次握手,而且其实建立连接和释放连接的这个过程是最耗时的,传输数据相反却不那么耗时。还有本地时间被修改导致响应头expires的缓存机制失效的问题~(后面会详细讲)
  • 常见的请求报文~

clipboard.png

于是出现了Http 1.1,这也是技术的发展必然结果~

  • Http 1.1出现,继承了Http1.0的优点,也克服了它的缺点,出现了keep-alive这个头部字段,它表示会在建立TCP连接后,完成首次的请求,并不会立刻断开TCP连接,而是保持这个连接状态~进而可以复用这个通道
  • Http 1.1并且支持请求管道化,“并行”发送请求,但是这个并行,也不是真正意义上的并行,而是可以让我们把先进先出队列从客户端(请求队列)迁移到服务端(响应队列)
例如:客户端同时发了两个请求分别来获取html和css,假如说服务器的css资源先准备就绪,服务器也会先发送html再发送css。
  • B站首页,就有keep-alive,因为他们也有IM的成分在里面。需要大量复用TCP连接~

clipboard.png

  • HTTP1.1好像还是无法解决队头阻塞的问题
实际上,现阶段的浏览器厂商采取了另外一种做法,它允许我们打开多个TCP的会话。也就是说,上图我们看到的并行,其实是不同的TCP连接上的HTTP请求和响应。这也就是我们所熟悉的浏览器对同域下并行加载6~8个资源的限制。而这,才是真正的并行!

Http 1.1的致命缺点:

  • 1.明文传输
  • 2.其实还是没有解决无状态连接的
  • 3.当有多个请求同时被挂起的时候 就会拥塞请求通道,导致后面请求无法发送
  • 4.臃肿的消息首部:HTTP/1.1能压缩请求内容,但是消息首部不能压缩;在现今请求中,消息首部占请求绝大部分(甚至是全部)也较为常见.
我们也可以用dns-prefetch和 preconnect tcp来优化~
<link rel="preconnect" href="//example.com" crossorigin>
<link rel="dns=prefetch" href="//example.com">
  • Tip: webpack可以做任何事情,这些都可以用插件实现

基于这些缺点,出现了Http 2.0

相较于HTTP1.1,HTTP2.0的主要优点有采用二进制帧封装,传输变成多路复用,流量控制算法优化,服务器端推送,首部压缩,优先级等特点。

HTTP1.x的解析是基于文本的,基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多。而HTTP/2会将所有传输的信息分割为更小的消息和帧,然后采用二进制的格式进行编码,HTTP1.x的头部信息会被封装到HEADER frame,而相应的RequestBody则封装到DATAframe里面。不改动HTTP的语义,使用二进制编码,实现方便且健壮。

多路复用

  • 所有的请求都是通过一个 TCP 连接并发完成。HTTP/1.x 虽然通过 pipeline 也能并发请求,但是多个请求之间的响应会被阻塞的,所以 pipeline 至今也没有被普及应用,而 HTTP/2 做到了真正的并发请求。同时,流还支持优先级和流量控制。当流并发时,就会涉及到流的优先级和依赖。即:HTTP2.0对于同一域名下所有请求都是基于流的,不管对于同一域名访问多少文件,也只建立一路连接。优先级高的流会被优先发送。图片请求的优先级要低于 CSS 和 SCRIPT,这个设计可以确保重要的东西可以被优先加载完

流量控制

  • TCP协议通过sliding window的算法来做流量控制。发送方有个sending window,接收方有receive window。http2.0的flow control是类似receive window的做法,数据的接收方通过告知对方自己的flow window大小表明自己还能接收多少数据。只有Data类型的frame才有flow control的功能。对于flow control,如果接收方在flow window为零的情况下依然更多的frame,则会返回block类型的frame,这张场景一般表明http2.0的部署出了问题。

服务器端推送

  • 服务器端的推送,就是服务器可以对一个客户端请求发送多个响应。除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。当浏览器请求一个html,服务器其实大概知道你是接下来要请求资源了,而不需要等待浏览器得到html后解析页面再发送资源请求。

首部压缩

  • HTTP 2.0 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;通信期间几乎不会改变的通用键-值对(用户代理、可接受的媒体类型,等等)只 需发送一次。事实上,如果请求中不包含首部(例如对同一资源的轮询请求),那么 首部开销就是零字节。此时所有首部都自动使用之前请求发送的首部。
  • 如果首部发生变化了,那么只需要发送变化了数据在Headers帧里面,新增或修改的首部帧会被追加到“首部表”。首部表在 HTTP 2.0 的连接存续期内始终存在,由客户端和服务器共同渐进地更新 。
  • 本质上,当然是为了减少请求啦,通过多个js或css合并成一个文件,多张小图片拼合成Sprite图,可以让多个HTTP请求减少为一个,减少额外的协议开销,而提升性能。当然,一个HTTP的请求的body太大也是不合理的,有个度。文件的合并也会牺牲模块化和缓存粒度,可以把“稳定”的代码or 小图 合并为一个文件or一张Sprite,让其充分地缓存起来,从而区分开迭代快的文件。
Demo的性能对比:

clipboard.png

Http的那些致命缺陷,并没有完全解决,于是有了https,也是目前应用最广的协议之一

HTTP+ 加密 + 认证 + 完整性保护 =HTTPS ?

可以这样认为~HTTP 加上加密处理和认证以及完整性保护后即是 HTTPS

  • 如果在 HTTP 协议通信过程中使用未经加密的明文,比如在 Web 页面中输入信用卡号,如果这条通信线路遭到窃听,那么信用卡号就暴露了。
  • 另外,对于 HTTP 来说,服务器也好,客户端也好,都是没有办法确认通信方的。

因为很有可能并不是和原本预想的通信方在实际通信。并且还需要考虑到接收到的报文在通信途中已经遭到篡改这一可能性。

  • 为了统一解决上述这些问题,需要在 HTTP 上再加入加密处理和认证等机制。我们把添加了加密及认证机制的 HTTP 称为 HTTPS
不加密的重要内容被wireshark这类工具抓到包,后果很严重~

HTTPS 是身披 SSL 外壳的 HTTP

  • HTTPS 并非是应用层的一种新协议。只是 HTTP 通信接口部分用 SSL(SecureSocket Layer)和 TLS(Transport Layer Security)协议代替而已。

通常,HTTP 直接和 TCP 通信。

  • 当使用 SSL 时,则演变成先和 SSL 通信,再由 SSL和 TCP 通信了。简言之,所谓 HTTPS,其实就是身披 SSL 协议这层外壳的HTTP。
  • 在采用 SSL 后,HTTP 就拥有了 HTTPS 的加密、证书和完整性保护这些功能。SSL 是独立于 HTTP 的协议,所以不光是 HTTP 协议,其他运行在应用层的 SMTP和 Telnet 等协议均可配合 SSL 协议使用。可以说 SSL 是当今世界上应用最为广泛的网络安全术。

clipboard.png

相互交换密钥的公开密钥加密技术 -----对称加密

clipboard.png

  • 在对 SSL 进行讲解之前,我们先来了解一下加密方法。SSL 采用一种叫做公开密钥加密(Public-key cryptography)的加密处理方式。
  • 近代的加密方法中加密算法是公开的,而密钥却是保密的。通过这种方式得以保持加密方法的安全性。
加密和解密都会用到密钥。没有密钥就无法对密码解密,反过来说,任何人只要持有密钥就能解密了。如果密钥被攻击者获得,那加密也就失去了意义。

HTTPS 采用混合加密机制

  • HTTPS 采用共享密钥加密和公开密钥加密两者并用的混合加密机制。
  • 但是公开密钥加密与共享密钥加密相比,其处理速度要慢。所以应充分利用两者各自的优势,将多种方法组合起来用于通信。在交换密钥环节使用公开密钥加密方式,之后的建立通信交换报文阶段则使用共享密钥加密方式。

HTTPS虽好,非对称加密虽好,但是不要滥用

HTTPS 也存在一些问题,那就是当使用 SSL 时,它的处理速度会变慢。

SSL 的慢分两种。一种是指通信慢。另一种是指由于大量消耗 CPU 及内存等资源,导致处理速度变慢。

  • 和使用 HTTP 相比,网络负载可能会变慢 2 到 100 倍。除去和 TCP 连接、发送 HTTP 请求 ? 响应以外,还必须进行 SSL 通信,因此整体上处理通信量不可避免会增加。
  • 另一点是 SSL 必须进行加密处理。在服务器和客户端都需要进行加密和解密的运算处理。因此从结果上讲,比起 HTTP 会更多地消耗服务器和客户端的硬件资源,导致负载增强。

针对速度变慢这一问题,并没有根本性的解决方案,我们会使用 SSL 加速器这种(专用服务器)硬件来改善该问题。该硬件为 SSL 通信专用硬件,相对软件来讲,能够提高数倍 SSL 的计算速度。仅在 SSL 处理时发挥 SSL加速器的功效,以分担负载。

为什么不一直使用 HTTPS

  • 既然 HTTPS 那么安全可靠,那为何所有的 Web 网站不一直使用 HTTPS?

其中一个原因是,因为与纯文本通信相比,加密通信会消耗更多的 CPU 及内存资源。如果每次通信都加密,会消耗相当多的资源,平摊到一台计算机上时,能够处理的请求数量必定也会随之减少。

  • 因此,如果是非敏感信息则使用 HTTP 通信,只有在包含个人信息等敏感数据时,才利用 HTTPS 加密通信。

特别是每当那些访问量较多的 Web 网站在进行加密处理时,它们所承担着的负载不容小觑。在进行加密处理时,并非对所有内容都进行加密处理,而是仅在那些需要信息隐藏时才会加密,以节约资源。

  • 除此之外,想要节约购买证书的开销也是原因之一。

要进行 HTTPS 通信,证书是必不可少的。而使用的证书必须向认证机构(CA)购买。证书价格可能会根据不同的认证机构略有不同。通常,一年的授权需要数万日元(现在一万日元大约折合 600 人民币)。那些购买证书并不合算的服务以及一些个人网站,可能只会选择采用HTTP 的通信方式。

clipboard.png

复习完了基本的协议,介绍下报文格式:

  • 请求报文格式

clipboard.png

  • 响应报文格式

clipboard.png

所谓响应头,请求头,其实都可以自己添加字段,只要前后端给对应的处理机制即可

Node.js代码实现响应头的设置


  if (config.cache.expires) {
                        res.setHeader("expries", new Date(Date.now() + (config.cache.maxAge * 1000)))
                    }
                    if (config.cache.lastModified) {
                        res.setHeader("last-modified", stat.mtime.toUTCString())
                    }
                    if (config.cache.etag) {
                        res.setHeader('Etag', etagFn(stat))
                    }
}

响应头的详解:

clipboard.png

本人的开源项目,手写的Node.js静态资源服务器,https://github.com/JinJieTan/...,欢迎 star~

浏览器的缓存策略:

  • 首次请求:

clipboard.png

  • 非首次请求:

clipboard.png

  • 用户行为与缓存:

clipboard.png

不能缓存的请求:

无法被浏览器缓存的请求如下:

  • HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache(HTTP1.0),或Cache-Control:max-age=0等告诉浏览器不用缓存的请求
  • 需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的
  • 经过HTTPS安全加密的请求(有人也经过测试发现,ie其实在头部加入Cache-Control:max-age信息,firefox在头部加入Cache-Control:Public之后,能够对HTTPS的资源进行缓寸)
  • 经过HTTPS安全加密的请求(有人也经过测试发现,ie其实在头部加入Cache-Control:max-age信息,firefox在头部加入Cache-Control:Public之后,能够对HTTPS的资源进行缓存,参考《HTTPS的七个误解》)
  • POST请求无法被缓存
  • HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存

即时通讯协议

从最初的没有websocket协议开始:

传统的协议无法服务端主动push数据,于是有了这些骚操作:
  • 轮询,在一个定时器中不停向服务端发送请求。
  • 长轮询,发送请求给服务端,直到服务端觉得可以返回数据了再返回响应,否则这个请求一直挂起~
  • 以上两种都有瑕疵,而且比较明显,这里不再描述。

为了解决实时通讯,数据同步的问题,出现了webSocket.

  • webSockets的目标是在一个单独的持久连接上提供全双工、双向通信。在Javascript创建了Web Socket之后,会有一个HTTP请求发送到浏览器以发起连接。在取得服务器响应后,建立的连接会将HTTP升级从HTTP协议交换为WebSocket协议。
  • webSocket原理: 在TCP连接第一次握手的时候,升级为ws协议。后面的数据交互都复用这个TCP通道。
  • 客户端代码实现:
  const ws = new WebSocket('ws://localhost:8080');
        ws.onopen = function () {
            ws.send('123')
            console.log('open')
        }
        ws.onmessage = function () {
            console.log('onmessage')
        }
        ws.onerror = function () {
            console.log('onerror')
        }
        ws.onclose = function () {
            console.log('onclose')
        }
  • 服务端使用 Node.js语言实现
const express = require('express')
const { Server } = require("ws");
const app = express()
const wsServer = new Server({ port: 8080 })
wsServer.on('connection', (ws) => {
    ws.onopen = function () {
        console.log('open')
    }
    ws.onmessage = function (data) {
        console.log(data)
        ws.send('234')
        console.log('onmessage' + data)
    }
    ws.onerror = function () {
        console.log('onerror')
    }
    ws.onclose = function () {
        console.log('onclose')
    }
});

app.listen(8000, (err) => {
    if (!err) { console.log('监听OK') } else {
        console.log('监听失败')
    }
})

webSocket的报文格式有一些不一样:

![图片上传中...]

  • 客户端和服务端进行Websocket消息传递是这样的:

    • 客户端:将消息切割成多个帧,并发送给服务端。
    • 服务端:接收消息帧,并将关联的帧重新组装成完整的消息。

即时通讯的心跳检测:

pingandpong

  • 服务端Go实现:
package main

import (
    "net/http"
    "time"

    "github.com/gorilla/websocket"
)

var (
    //完成握手操作
    upgrade = websocket.Upgrader{
       //允许跨域(一般来讲,websocket都是独立部署的)
       CheckOrigin:func(r *http.Request) bool {
            return true
       },
    }
)

func wsHandler(w http.ResponseWriter, r *http.Request) {
   var (
         conn *websocket.Conn
         err error
         data []byte
   )
   //服务端对客户端的http请求(升级为websocket协议)进行应答,应答之后,协议升级为websocket,http建立连接时的tcp三次握手将保持。
   if conn, err = upgrade.Upgrade(w, r, nil); err != nil {
        return
   }

    //启动一个协程,每隔5s向客户端发送一次心跳消息
    go func() {
        var (
            err error
        )
        for {
            if err = conn.WriteMessage(websocket.TextMessage, []byte("heartbeat")); err != nil {
                return
            }
            time.Sleep(5 * time.Second)
        }
    }()

   //得到websocket的长链接之后,就可以对客户端传递的数据进行操作了
   for {
         //通过websocket长链接读到的数据可以是text文本数据,也可以是二进制Binary
        if _, data, err = conn.ReadMessage(); err != nil {
            goto ERR
     }
     if err = conn.WriteMessage(websocket.TextMessage, data); err != nil {
         goto ERR
     }
   }
ERR:
    //出错之后,关闭socket连接
    conn.Close()
}

func main() {
    http.HandleFunc("/ws", wsHandler)
    http.ListenAndServe("0.0.0.0:7777", nil)
}

客户端的心跳检测(Node.js实现):

this.heartTimer = setInterval(() => {
      if (this.heartbeatLoss < MAXLOSSTIMES) {
        events.emit('network', 'sendHeart');
        this.heartbeatLoss += 1;
        this.phoneLoss += 1;
      } else {
        events.emit('network', 'offline');
        this.stop();
      }
      if (this.phoneLoss > MAXLOSSTIMES) {
        this.PhoneLive = false;
        events.emit('network', 'phoneDisconnect');
      }
    }, 5000);

自定义即时通信协议:

new Socket开始:

  • 目前即时通讯大都使用现有大公司成熟的SDK接入,但是逼格高些还是自己重写比较好。
  • 打个小广告,我们公司就是自己定义的即时通讯协议~招聘一位高级前端,地点深圳-深南大道,做跨平台IM桌面应用开发的~
  • 客户端代码实现(Node.js):

const {Socket} = require('net') 
const tcp = new Socket()
tcp.setKeepAlive(true);
tcp.setNoDelay(true);
//保持底层tcp链接不断,长连接
指定对应域名端口号链接
tcp.connect(80,166.166.0.0)
建立连接后
根据后端传送的数据类型 使用对应不同的解析
readUInt8 readUInt16LE readUInt32LE readIntLE等处理后得到myBuf 
const myBuf = buffer.slice(start);//从对应的指针开始的位置截取buffer
const header = myBuf.slice(headstart,headend)//截取对应的头部buffer
const body = JSON.parse(myBuf.slice(headend-headstart,bodylength).tostring())
//精确截取数据体的buffer,并且转化成js对象
即时通讯强烈推荐使用Golang,GRPC,Prob传输数据。

上面的一些代码,都在我的开源项目中:

觉得写得不错,可以点个赞支持下,文章也借鉴了一下其他大佬的文章,但是地址都贴上来了~ 欢迎gitHub点个star哦~
查看原文

赞 177 收藏 141 评论 0

爱学习的小伙子 发布了文章 · 8月10日

获取任意(定位非fixed)DOM元素距离页面顶部HTML的距离

function toTopHeight(el) {
    var top_height = el.offsetTop;      //先保存当前元素的offsetTop值
      if(el&&el.nodeName!='HTML') {
          el = el.parentElement;
        while(el&&el.nodeName!="HTML"){//当当前元素不是顶部html标签时,继续迭代
            if(getComputedStyle(el).position!=='static'){
            //只有当元素有定位时,才将此元素的offsetTop值加入到结果中,因为offsetTop的值是距离自身到离自身最近的有定位的父元素的内壁的距离
                top_height+=el.offsetTop;
            }
            el = el.parentElement;
          }
      }
      return top_height;
}

有不懂或者错误的地方可以在下方评论区交流讨论

查看原文

赞 0 收藏 0 评论 0

爱学习的小伙子 赞了回答 · 4月18日

解决一段关于如何实现instanceof的代码

这不是重复设置,每次循环会检查left 是否为 null 和是否等于 prototype,如果条件都不成立,那就把left.__proto__赋值left
换成下面这样是不是好理解一些了,当第一次循环的时候,上面的if语句的obj === left.__proto__,如果if都不满足,在结尾重新赋值,进入第二次循环的时候,obj === left.__proto__.__proto__.然后一次次循环,直到obj === null或者obj === prototype结束.

function instanceOf(left, right) {
  // 获得类型的原型
  let prototype = right.prototype
  // 获得对象的原型
  obj = left.__proto__
  // 判断对象的类型是否等于类型的原型
  while (true) {
    if (obj === null) return false
    if (obj === prototype) return true
    obj = obj.__proto__
  }
}

关注 2 回答 2

爱学习的小伙子 发布了文章 · 4月17日

字节跳动前端实习二面

1 冒泡排序时间复杂度?为什么?O(n2)的含义?十个数字需要比较多少次
2 手写斐波那契数列实现?这个问题的递归解如何优化
3 http状态码:502 401 403 301 302 304
4 缓存的使用,什么时候会用到304 什么时候不会发送请求?
5 数组去重有哪些方法
6 数组的reduce方法如何实现求和运算,实现reduce方法
7 数组判断方法,实现instanceof
8

//---------------------分割线--------------------------
1 n2,双重循环,时间复杂度与系数无关。最多需要45次
2 `function f(n){

if(n<2){ return 1 }
return f(n-1)+f(n-2)`
只想到了用中间变量存储中间值,但是代码写不出来,没刷题算法功底太差了,后面找同学讨论了一下递归解的优化如下:
`var a = 1;var b=1;     //初始化前两项
function f(n){
    if(n<2){return 1}
    a = f(n-1)
    b = a-b             //这里表示的是第n-2项=第n-1项减去第 n-3项
    return a+b;
`

3 状态码参考此处:https://www.cnblogs.com/xflon...
4 http缓存策略,考来考去不多说了
5 先说了两个循环的,没说完就下一题了,emmm。。。我还有Set方法没说。。。
6 arr.reduce((a,b)=>a+b,0) 然后底层实现是真不会,学会了再来补充
7 Array.isArray(), Object.prototype.toString.call(arr),arr instanceof Array 然后只写了判断数组的instanceof,对不对我就不清楚了

`arr.__proto__  == Array.prototype`感觉应该先用typeof判断一下,不然arr有没有__proto__都不知道

8

查看原文

赞 0 收藏 0 评论 0

爱学习的小伙子 发布了文章 · 4月16日

腾讯前端实习一面

1 http 304 状态码
2 为什么会出现304,讲到http头部缓存字段有哪些
3 快排的时间复杂度,最坏的情况有什么避免方法?
4 算法题:给定一篇英文文章,找到出现次数最多的那个单词?
5 DNS查找的过程?
总结: 还有的没记起来,答得不好,就没继续问了。主要是考察了计算机网络和数据结构的知识

查看原文

赞 1 收藏 1 评论 0

爱学习的小伙子 发布了文章 · 4月16日

深信服前端一面

1 首先自我介绍一下
2 为什么学习前端,为什么转计算机
3 promise有哪些状态,promise.all是什么,如何终止一个promise(这个没查到资料)
4 forEach和map的区别

都接受一个回调,forEach返回值是undefined,map返回一个新数组,map不会对原数组造成影响

5 cookie、session和sessionStorage的区别
6 对node了解如何?express如何鉴别身份?
7 还有一些简单的没记起来

查看原文

赞 0 收藏 0 评论 0

爱学习的小伙子 发布了文章 · 4月13日

字节跳动前端一面回顾

1 自我介绍
2 es6了解什么

答:promise、变量声明、然后没想起来
接着问了let const var的区别

3 一个变量关于输出的问题,很简单,但。。。感觉挂在这了,直接给自己说晕了,说到底,是自己基础太薄弱了

`var b=2
 if(true){
    var a = 3;
    var b = 3;
    var c = 1;
    const d = 6;
 }
 console.log(a)
 console.log(b)
 console.log(c)
 console.log(d)
 var a;
 var d = 4
 
`

4 编程题 将[a,b,c,d]转换成{a:{b:{c:'d'}}}
5 编程题 实现圣杯布局
6 编程题 统计某个页面中所用到的标签
7 flex的应用场景
8 从输入网址到展示经历了什么过程?之后引申到服务器express框架,当服务器收到你的请求,服务器会做反应?详细说一下
9 回流和重绘是什么,什么时候会发生?

查看原文

赞 1 收藏 1 评论 0

爱学习的小伙子 赞了文章 · 4月5日

localStorage、sessionStorage、Cookie的区别及用法

localStorage、sessionStorage、Cookie的区别及用法

图片描述

webstorage

webstorage是本地存储,存储在客户端,包括localStorage和sessionStorage。

localStorage

localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。

sessionStorage

sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。源生接口可以接受,亦可再次封装来对Object和Array有更好的支持。

localStorage和sessionStorage使用时使用相同的API:

 localStorage.setItem("key","value");//以“key”为名称存储一个值“value”

    localStorage.getItem("key");//获取名称为“key”的值

    localStorage.removeItem("key");//删除名称为“key”的信息。

    localStorage.clear();​//清空localStorage中所有信息

简单的举个例子来了解一下他们的用法

仿一下京东官网顶部的广告关闭,效果为第一次进入官网会出现广告,然后点击关闭,刷新网页不会再显示广告,但是当清除localStorage存入的数据,刷新网页会再显示广告。
html代码

<div class="header">
    <div class="header-a">
        <a href=""></a>
        <i class="close">x</i>
    </div>
</div>    

css代码

.header{
    width:100%;
    height:80px;
    background:#000;
}
.header-a{
    width:1190px;
    margin:0 auto;
    position:relative;
    background:url("images/1.jpg") no-repeat;
}
.header-a a{
    width:100%;
    height:80px;
    display:block;
}
.close{
    cursor:pointer;
    color:#fff;
    position:absolute;
    top:5px;
    right:5px;
    background:rgb(129, 117, 117);
    width: 20px;
    text-align: center;
    line-height: 20px;
}    

js代码

//localStorage方法
<script data-original="../js/jquery.min.js"></script>
function haxi(){
        //判断localStorage里有没有isClose
        if(localStorage.getItem("isClose")){             
            $(".header").hide();
        }else{
            $(".header").show();
        }
        //点击关闭隐藏图片存取数据
        $(".close").click(function(){
            $(".header").fadeOut(1000);

            localStorage.setItem("isClose", "1"); 
        })
    }
    haxi();

作用域不同

不同浏览器无法共享localStorage或sessionStorage中的信息。相同浏览器的不同页面间可以共享相同的 localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享sessionStorage的信息。这里需要注意的是,页面及标 签页仅指顶级窗口,如果一个标签页包含多个iframe标签且他们属于同源页面,那么他们之间是可以共享sessionStorage的。

Cookie

生命期为只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。 存放数据大小为4K左右 。有个数限制(各浏览器不同),一般不能超过20个。与服务器端通信:每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题。但Cookie需要程序员自己封装,源生的Cookie接口不友好(http://www.jb51.net/article/6...
)。
js代码

//Cookie方法
<script data-original="../js/cookie.js"></script>//Cookie函数自己封装引入
function haxi(){
        if(getCookie("isClose")){             
            $(".header").hide();
        }else{
            $(".header").show();
        }
        
        $(".close").click(function(){
            $(".header").fadeOut(1000);

            setCookie("isClose", "1","s10");
        })
    }
    haxi();

cookie的优点:具有极高的扩展性和可用性

1.通过良好的编程,控制保存在cookie中的session对象的大小。
2.通过加密和安全传输技术,减少cookie被破解的可能性。
3.只有在cookie中存放不敏感的数据,即使被盗取也不会有很大的损失。
4.控制cookie的生命期,使之不会永远有效。这样的话偷盗者很可能拿到的就   是一个过期的cookie。

cookie的缺点:

1.cookie的长度和数量的限制。每个domain最多只能有20条cookie,每个cookie长度不能超过4KB。否则会被截掉。
2.安全性问题。如果cookie被人拦掉了,那个人就可以获取到所有session信息。加密的话也不起什么作用。
3.有些状态不可能保存在客户端。例如,为了防止重复提交表单,我们需要在服务端保存一个计数器。若吧计数器保存在客户端,则起不到什么作用。

localStorage、sessionStorage、Cookie共同点:都是保存在浏览器端,且同源的。

查看原文

赞 95 收藏 100 评论 0

爱学习的小伙子 赞了文章 · 4月4日

20道HTML基础面试题(附答案)

以下是我整理的一些HTML的基础面试体,并自己整理了答案。

1 DOCTYPE有什么作用?标准模式与混杂模式如何区分?它们有何意义?

告诉浏览器使用哪个版本的HTML规范来渲染文档。DOCTYPE不存在或形式不正确会导致HTML文档以混杂模式呈现。
标准模式(Standards mode)以浏览器支持的最高标准运行;混杂模式(Quirks mode)中页面是一种比较宽松的向后兼容的方式显示。

2 HTML5为什么只需要写 <!DOCTYPE HTML>?

HTML5不基于SGML(Standard Generalized Markup Language 标准通用标记语言),因此不需要对DTD(DTD 文档类型定义)进行引用,但是需要DOCTYPE来规范浏览器行为。

HTML4.01基于SGML,所以需要引用DTD。才能告知浏览器文档所使用的文档类型,如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

3 行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

行内元素:a span img input select
块级元素:div ul ol li dl dt dd h1 p
空元素:<br> <hr> <link> <meta>

4 页面导入样式时,使用link和@import有什么区别?

相同的地方,都是外部引用CSS方式,区别:

  1. link是xhtml标签,除了加载css外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS
  2. link引用CSS时候,页面载入时同时加载;@import需要在页面完全加载以后加载,而且@import被引用的CSS会等到引用它的CSS文件被加载完才加载
  3. link是xhtml标签,无兼容问题;@import是在css2.1提出来的,低版本的浏览器不支持
  4. link支持使用javascript控制去改变样式,而@import不支持
  5. link方式的样式的权重高于@import的权重
  6. import在html使用时候需要<style type="text/css">标签

5 无样式内容闪烁(FOUC)Flash of Unstyle Content

@import导入CSS文件会等到文档加载完后再加载CSS样式表。因此,在页面DOM加载完成到CSS导入完成之间会有一段时间页面上的内容是没有样式的。

解决方法:使用link标签加载CSS样式文件。因为link是顺序加载的,这样页面会等到CSS下载完之后再下载HTML文件,这样先布局好,就不会出现FOUC问题。

6 介绍一下你对浏览器内核的理解?

主要分成两部分:渲染引擎(Layout Engine或Rendering Engine)和JS引擎。

渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。
JS引擎:解析和执行javascript来实现网页的动态效果。

最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。

7 常见的浏览器内核有哪些?

  1. Trident( MSHTML ):IE MaxThon TT The World 360 搜狗浏览器
  2. Geckos:Netscape6及以上版本 FireFox Mozilla Suite/SeaMonkey
  3. Presto:Opera7及以上(Opera内核原为:Presto,现为:Blink)
  4. Webkit:Safari Chrome

8 HTML5有哪些新特性,移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分HTML和HTML5

新增加了图像、位置、存储、多任务等功能。
新增元素:

  1. canvas
  2. 用于媒介回放的video和audio元素
  3. 本地离线存储。localStorage长期存储数据,浏览器关闭后数据不丢失;sessionStorage的数据在浏览器关闭后自动删除
  4. 语意化更好的内容元素,比如 article footer header nav section
  5. 位置API:Geolocation
  6. 表单控件,calendar date time email url search
  7. 新的技术:web worker(web worker是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能。您可以继续做任何愿意做的事情:点击、选取内容等等,而此时 web worker 在后台运行) web socket
  8. 拖放API:drag、drop

移除的元素:

  1. 纯表现的元素:basefont big center font s strike tt u
  2. 性能较差元素:frame frameset noframes

区分:

  1. DOCTYPE声明的方式是区分重要因素
  2. 根据新增加的结构、功能来区分

9 简述一下你对HTML语义化的理解?

  1. 去掉或丢失样式的时候能够让页面呈现出清晰的结构。
  2. 有利于SEO和搜索引擎建立良好沟通,有助于爬虫抓取更多的信息,爬虫依赖于标签来确定上下文和各个关键字的权重。
  3. 方便其它设备解析。
  4. 便于团队开发和维护,语义化根据可读性。

10 HTML5的文件离线储存怎么使用,工作原理是什么?

在线情况下,浏览器发现HTML头部有manifest属性,它会请求manifest文件,如果是第一次访问,那么浏览器就会根据manifest文件的内容下载相应的资源,并进行离线存储。如果已经访问过并且资源已经离线存储了,那么浏览器就会使用离线的资源加载页面。然后浏览器会对比新的manifest文件与旧的manifest文件,如果文件没有发生改变,就不会做任何操作,如果文件改变了,那么就会重新下载文件中的资源,并且进行离线存储。例如,

在页面头部加入manifest属性

<html manifest='cache.manifest'>

在cache.manifest文件中编写离线存储的资源

CACHE MANIFEST
#v0.11
CACHE:
js/app.js
css/style.css
NETWORK:
Resourse/logo.png
FALLBACK:
 //offline.html

11 cookies,sessionStorage和localStorage的区别?

共同点:都是保存在浏览器端,且是同源的。

区别:

  1. cookies是为了标识用户身份而存储在用户本地终端上的数据,始终在同源http请求中携带,即cookies在浏览器和服务器间来回传递,而sessionstorage和localstorage不会自动把数据发给服务器,仅在本地保存。
  2. 存储大小的限制不同。cookie保存的数据很小,不能超过4k,而sessionstorage和localstorage保存的数据大,可达到5M。
  3. 数据的有效期不同。cookie在设置的cookie过期时间之前一直有效,即使窗口或者浏览器关闭。sessionstorage仅在浏览器窗口关闭之前有效。localstorage始终有效,窗口和浏览器关闭也一直保存,用作长久数据保存。
  4. 作用域不同。cookie在所有的同源窗口都是共享;sessionstorage不在不同的浏览器共享,即使同一页面;localstorage在所有同源窗口都是共享

12 iframe框架有那些优缺点?

优点:

  1. iframe能够原封不动的把嵌入的网页展现出来。
  2. 如果有多个网页引用iframe,那么你只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷。
  3. 网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用。
  4. 如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决。

缺点:

  1. 搜索引擎的爬虫程序无法解读这种页面
  2. 框架结构中出现各种滚动条
  3. 使用框架结构时,保证设置正确的导航链接。
  4. iframe页面会增加服务器的http请求

13 label的作用是什么? 是怎么用的?

label标签用来定义表单控件间的关系,当用户选择该标签时,浏览器会自动将焦点转到和标签相关的表单控件上。label 中有两个属性是非常有用的, FOR和ACCESSKEY。
FOR属性功能:表示label标签要绑定的HTML元素,你点击这个标签的时候,所绑定的元素将获取焦点。例如,

<Label FOR="InputBox">姓名</Label><input ID="InputBox" type="text"> 

ACCESSKEY属性功能:表示访问label标签所绑定的元素的热键,当您按下热键,所绑定的元素将获取焦点。例如,

<Label FOR="InputBox" ACCESSKEY="N">姓名</Label><input ID="InputBox" type="text">

14 HTML5的form如何关闭自动完成功能?

HTML的输入框可以拥有自动完成的功能,当你往输入框输入内容的时候,浏览器会从你以前的同名输入框的历史记录中查找出类似的内容并列在输入框下面,这样就不用全部输入进去了,直接选择列表中的项目就可以了。但有时候我们希望关闭输入框的自动完成功能,例如当用户输入内容的时候,我们希望使用AJAX技术从数据库搜索并列举而不是在用户的历史记录中搜索。

方法:

  1. 在IE的internet选项菜单中里的自动完成里面设置
  2. 设置form输入框的autocomplete为on或者off来来开启输入框的自动完成功能

15 如何实现浏览器内多个标签页之间的通信?

  1. WebSocket SharedWorker
  2. 也可以调用 localstorge、cookies 等本地存储方式。 localstorge 在另一个浏览上下文里被添加、修改或删除时,它都会触发一个事件,我们通过监听事件,控制它的值来进行页面信息通信。

注意:Safari 在无痕模式下设置 localstorge 值时会抛出QuotaExceededError 的异常

16 webSocket如何兼容低浏览器?

  1. Adobe Flash Socket ActiveX HTMLFile (IE) 基于 multipart 编码发送 XHR 基于长轮询的 XHR
  2. 引用WebSocket.js这个文件来兼容低版本浏览器。

16 页面可见性(Page Visibility)API 可以有哪些用途?

  1. 通过visibility state的值得检测页面当前是否可见,以及打开网页的时间。
  2. 在页面被切换到其他后台进程时,自动暂停音乐或视频的播放。

17 如何在页面上实现一个圆形的可点击区域?

  1. map+area或者svg
  2. border-radius
  3. 纯js实现,一个点不在圆上的算法

18 实现不使用 border 画出1px高的线,在不同浏览器的Quirks mode和CSS Compat模式下都能保持同一效果

<div style="height:1px;overflow:hidden;background:red"></div>

19 网页验证码是干嘛的,是为了解决什么安全问题?

  1. 区分用户是计算机还是人的程序;
  2. 可以防止恶意破解密码、刷票、论坛灌水;

20 title与h1的区别、b与strong的区别、i与em的区别?

title属性没有明确意义,只表示标题;h1表示层次明确的标题,对页面信息的抓取也有很大的影响
strong标明重点内容,语气加强含义;b是无意义的视觉表示
em表示强调文本;i是斜体,是无意义的视觉表示
视觉样式标签:b i u s
语义样式标签:strong em ins del code

21 元素的alt和title有什么异同?

在alt和title同时设置的时候,alt作为图片的替代文字出现,title是图片的解释文字。

持续更新中...

查看原文

赞 28 收藏 94 评论 1

爱学习的小伙子 发布了文章 · 4月3日

个人理解的js继承,欢迎批评指正

6中原型链继承方式

1 原型链继承

    原型链继承是让子类的原型prototype属性指向父类的新实例,实现的本质是重写原型对象,子类拥有父类的方法,所有实例共享原型上的变量和方法,如果有重写,则会反映到所有实例上

2 构造函数

    在子类函数中调用父类函数(SuperType.call(this)),1 每个子类拥有父类中属性方法的副本,解决了上面的问题,2 方法在子类中定义,无法很好地实现复用 3, 可以传递参数

3 原型链+构造函数

    首先在子类中调用父类的方法,再让子类的原型指向父类的一个新实例,并让子类原型上的构造函数指向父类

4 原型式继承

    在函数中,首先传入要继承的对象,然后创建一个构造函数,让构造函数的prototype属性指向传入对象,,然后新建一个构造函数并返回。然后使用这个这个函数来创建新对象实例,这些实例的__proto__指向person对象

5 寄生式继承~~~~

    寄生式继承就是把原型式继承再次封装,然后在对象上扩展新的方法,再把新对象返回,采用Object.create(原型对象),再在新实例上添加方法,最会返回创建的新对象

6 寄生组合式继承

    在子类方法中调用父类,并添加自己的私有属性,第二步继承,创建一个新实例,并让新实例的原型指向父类的原型,让子类的原型指向这个实例,3 修复Constructor,子类原型上的Constructor指回子类自身(subType) 4
查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 2 次点赞
  • 获得 4 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 4 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2019-10-24
个人主页被 143 人浏览