1.输入URL到打开网页,经历了哪些过程?
- 用户在浏览器地址栏中输入URL(统一资源定位符)。
- 浏览器将该URL发送到DNS(域名系统)服务器,以获取与之对应的IP地址。
- DNS服务器返回IP地址给浏览器。
- 浏览器利用IP地址与Web服务器建立TCP(传输控制协议)连接。
- 浏览器发出HTTP(超文本传输协议)请求,其中包括请求方法、文件路径、HTTP版本、请求头等。
- Web服务器接收到请求后,通过HTTP响应返回所请求的资源,响应头中包含响应状态码、响应内容的类型、长度等信息。
- 浏览器接收到响应后,根据响应状态码判断请求是否成功,并解析响应内容。
- 浏览器将解析后的内容渲染到页面上,包括HTML、CSS、JavaScript等。
- 若页面中包含其他资源(如图片、视频等),浏览器将重复以上过程,请求相应的资源。
- 浏览器将页面呈现给用户,用户可进行交互操作。
2.http请求常用的方法?
GET:用于请求资源,一般是获取数据。
POST:用于提交数据到服务端,比如表单数据等。
PUT:用于更新资源,客户端提交一个更新后的实体,服务端对原有实体进行替换。
DELETE:用于删除资源,客户端请求服务端删除指定的资源。
3.http2.0和http1.0有哪些区别?
HTTP/1.0和HTTP/1.1之间的主要区别如下:
请求管道化:HTTP/1.1支持请求管道化,允许客户端在不等待响应的情况下同时发送多个请求,而HTTP/1.0不支持请求管道化。
持久连接:HTTP/1.1支持持久连接,允许客户端和服务器之间的多个请求和响应使用同一个TCP连接,而HTTP/1.0默认情况下不支持持久连接。
分块传输编码:HTTP/1.1引入了一种称为分块传输编码的方式,可将消息分成多个块,这些块可以分别传输。这使得服务器能够在处理请求时逐步生成响应,而不必等待整个响应的构建完成。
缓存处理:HTTP/1.1对缓存处理进行了改进,增加了一些缓存头部控制字段,如Cache-Control和ETag,使得缓存更加智能化,更加灵活。
HTTP/2.0相对于HTTP/1.x的主要区别如下:
二进制分帧:HTTP/2.0采用二进制格式对数据进行分帧,使得HTTP报文更加高效和明确,并且可以更灵活地进行流控制。
多路复用:HTTP/2.0支持多路复用,允许客户端和服务器之间通过一个TCP连接同时传输多个请求和响应,从而提高网络效率。
服务器推送:HTTP/2.0支持服务器推送,允许服务器在不经过客户端明确请求的情况下主动向客户端发送资源,提高了 Web 性能。
首部压缩:HTTP/2.0使用了一种称为HPACK的首部压缩算法,可以减少 HTTP 报文的首部大小,从而减少网络带宽和延迟。
4.get方法和post方法有什么区别?只有安全性方面的区别吗?
- 请求参数的传递方式:GET请求参数在URL中传递,而POST请求参数在请求体中传递。
- 请求的长度限制:GET请求URL长度受限,对于过长的请求参数会被截取或者被浏览器拒绝,而POST请求中的请求体没有长度限制。
- 安全性:GET请求参数会被保存在浏览器的历史记录中,容易被窃取,而POST请求参数则相对安全。
- 缓存处理:GET请求默认可以被浏览器缓存,而POST请求则不会被缓存。
- 请求语义:GET请求主要用于获取资源,POST请求主要用于提交数据。
5.单页面应用如何实现复杂的应用?如何根据路由来渲染?实现原理是什么?如何跟浏览器共同完成的?
单页面应用(Single Page Application,SPA)可以通过前端框架(如React、Vue、Angular等)来实现复杂的应用。这些框架都有自己的路由机制,可以根据路由来渲染不同的组件。
实现原理是通过JavaScript动态地操作DOM,根据不同的路由动态地渲染不同的组件。当用户在应用中点击一个链接或者输入一个URL时,路由会解析这个URL并根据解析结果来确定要渲染哪个组件。同时,浏览器也会根据路由信息来更新URL,并将渲染的组件呈现给用户。应用内部的跳转也可以通过监听路由变化来实现。
为了更好地支持路由,浏览器提供了History API,它允许JS通过pushState和replaceState方法来更新浏览器的URL,并且可以监听popstate事件来处理浏览器前进/后退时URL的变化。基于这个API,前端框架可以实现自己的路由机制。
6.对于前后端分离的项目,用户登录之后请求后续的接口是如何去验证用户的身份?(JWT)
在前后端分离的项目中,由于前后端是独立部署的,因此需要一种机制来实现用户身份认证和授权。JWT (JSON Web Token) 是一种传输信息的安全协议,用于在客户端和服务器之间传递身份信息。它包含了用户的信息和一些元数据,并进行数字签名,以保证传输过程中不被篡改。
在用户登录之后,后端会生成一个 JWT,并将其返回给前端。前端在后续请求中,在请求头中携带该 JWT,后端通过对 JWT 进行解密和验证签名,来确认用户的身份信息。如果验证成功,则认为该用户已经登录,可以继续访问其他的接口。否则,认为该用户未登录,需要重新进行登录操作。
通过这种方式,可以实现在前后端分离的项目中,对用户身份信息的验证和授权,提高了系统的安全性和可维护性。同时,JWT 也具有跨平台和可扩展的特点,在很多场景下被广泛应用。
7.说一说JWT的原理,由谁产生的?前端得到token后如何使用?后续请求如何使用token?怎么验证用户身份?
JWT即JSON Web Token,是一种用于身份验证的开放标准(RFC 7519)。JWT由三部分组成:头部、载荷和签名。其中,头部包含加密算法和类型(JWT)信息;载荷包含要传递的信息,如用户ID、角色等;签名是对头部和载荷进行加密后生成的签名,用于防止伪造和篡改。
JWT的产生是由前后端分离的开发需求而来的。在前后端分离的情况下,用户的身份验证需要通过token进行,JWT作为一种轻量级的身份验证机制,被广泛应用于前后端分离的应用开发中。
前端在得到JWT后,可以将token存储到本地浏览器的localStorage或cookie中,以备后续请求使用。在发送后续请求时,在请求的头部中添加Authorization字段,并在字段值中添加Bearer和token,例如:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
后端在收到请求时,会解析Authorization字段,验证token的合法性,并从载荷中获取用户信息进行身份验证。
验证用户身份的过程中,后端会对比token中的信息和数据库中的信息,以确保用户的身份是合法的。如果验证失败,后端会返回401状态码,说明该请求需要身份验证。
总之,JWT是一种基于token的身份验证机制,它通过加密和签名来保证token的完整性和安全性。前端在得到JWT后,可以将其存储到本地,用于后续请求的身份验证;后端在收到请求时,会对token进行解析和验证,从而验证用户的身份。
8.介绍一下事件循环机制
事件循环(Event Loop)是一种程序设计的模式,主要用于处理异步操作,例如用户输入、网络请求等。
事件循环机制的基本流程如下:
- 从事件队列中取出一个事件
- 执行这个事件对应的回调函数
- 检查是否有待执行的微任务(Promise、MutationObserver等),如果有则依次执行
- 检查是否有待执行的宏任务(setTimeout、setInterval、I/O操作等),如果有则执行最早的一个宏任务
- 如果事件队列为空且没有微任务需要执行,则进入休眠状态,等待新事件的到来
在JavaScript中,事件循环机制是由浏览器或Node.js运行时环境来实现的。如果某一时刻代码阻塞了事件循环,那么就会导致应用程序无法处理事件,造成页面卡顿等问题。
因此,在编写JavaScript代码时,需要避免长时间的同步操作,以保证事件循环的正常运转。可以使用异步编程方式(如Promise、async/await等)来处理异步操作,或者使用Web Worker来将一些耗时的计算放到单独的线程中。
9.如何实现一个按照一定周期来运行的任务?计时是谁在做计时?
实现一个按照一定周期来运行的任务可以使用定时器(timer)或者循环检测的方式。
使用定时器的方式,可以使用系统提供的定时器类库或者第三方定时器插件,比如在JavaScript中可以使用setInterval() 或者**setTimeout()**函数来实现。在Python中可以使用内置的time模块或者第三方的APScheduler来实现定时任务。
使用循环检测的方式,可以在程序主循环中添加一个计时器,每经过一定时间就执行一次任务。计时器可以是程序内部的一个变量或者使用系统提供的时间函数来实现,比如在Python中可以使用time模块的time()函数来获取当前时间,计算时间差来实现计时器。
在任何一种方式下,计时都是由系统或者程序来做计时,一般都是通过获取系统时间或者内部计数器来实现的。
10.setInterval和setTimeout有什么区别?
两者的区别在于定时器的触发方式 和执行次数。
setInterval函数是在指定的时间间隔内重复执行指定的代码,即定时器会一直执行,直到调用clearInterval()函数停止执行。而setTimeout函数是在指定的时间后执行一次指定的代码,即定时器只会执行一次。
另外,两者的参数也有所不同。setInterval函数有两个参数:第一个参数是要重复执行的函数,第二个参数是时间间隔;而setTimeout函数也有两个参数:第一个参数是要执行的函数,第二个参数是等待的时间。
总之,setInterval和setTimeout函数用途不同,具体使用要根据需求来选择。
11.在比较新的JS语法中为什么不会使用var?
在比较新的JS语法中,不太会使用var关键字,主要是因为var存在变量提升的问题。使用var声明的变量会在整个作用域中被提升到声明语句的顶部,这可能会导致一些意外结果。而使用let和const声明的变量不存在变量提升的问题,它们的作用域也更加明确和安全。另外,使用const声明的变量是不可变的,有利于减少不必要的变量修改,提高代码的可维护性和安全性。因此,在比较新的JS语法中,更推荐使用let和const关键字来声明变量。
12.let和var有什么区别?
在Javascript中,let和var都是用来声明一个变量的关键字,但它们有一些区别。
作用域:var 声明的变量是函数级作用域,只能在函数内部访问,而let声明的变量是块级作用域,只能在块级作用域内部访问。
变量提升:使用var声明的变量,会经过变量提升而在函数或全局作用域的顶部声明,所以在声明前使用该变量是可以正常访问的,但是使用let声明的变量是不存在变量提升的。
重复声明:在同一个作用域内,使用var重复声明同一个变量是允许的,而使用let重复声明同一个变量会报错。
迭代变量:在for循环中,使用var声明的迭代变量在循环完成后仍然存在于循环作用域中,而使用let声明的迭代变量在循环完毕后会被销毁。
总结:let更加严格,更具有局部性,而var更加松散和全局。建议在开发中使用let来声明变量,避免出现不必要的错误和代码行为的意外结果。
13.算法:有一个无序的大数组,这个数组很大,找出里面前N大的元素
一种常见的解法是使用堆排序算法。具体步骤如下:
建立一个大小为N的小根堆(最小堆)。
遍历整个数组,对于每个元素,如果它比堆顶元素大,则用它替换堆顶元素,并进行下滤操作。
遍历完整个数组后,堆中剩下的N个元素就是前N大的元素。
时间复杂度为O(nlogN),空间复杂度为O(N)。