2020-字节-前端-面试

   日期:2020-11-17     浏览:105    评论:0    
核心提示:1.先介绍一些自己会的语言,主要是后端我只会NodeJS,他问我简历上还写了python,会不会,我说只学了一些,不是很会。2.了解跨域吗?3.介绍一下http缓存?4.介绍一些IO模型?5.了解Node模型吗?6.了解mysql吗?了解sql索引吗?数据库里数据量很大,如何快速搜索。7.了解进程和线程吗?CPU处理的基本单位是什么?8.介绍一下CPU处理的算法?9.线程死锁是什么?10.给你一个网站的url,请写出这个url内所有url以及通过这些url之后跳转的所

1.先介绍一些自己会的语言,主要是后端

2.了解跨域吗?

域:一个网站的网址组成包括协议名,子域名,主域名,端口号。比如https://www.github.com/80。其中https是协议名,www.github.com是子域名,github.com是主域名,端口号是80,当在在页面中从一个url请求数据时,如果这个url的协议名、子域名、主域名、端口号任意一个有一个不同,就会产生跨域问题。即使是在 http://localhost:80/ 页面请求 http://127.0.0.1:80/ 也会有跨域问题(因为域名不一样)。这里所有的域是指协议\域名\端口号的合集,同域就是协议域名端口号均相同

跨域问题是浏览器同源策略限制,当前域名的js只能读取同域下的窗口属性。 

同源策略:在前端开发过程中,常见的HTML标签,如<a/>,<form/>,<img/>,<script/>,<iframe/>以及ajax操作都可以指向一个资源地址或者说可以发起对一个资源的请求,那么这里所说的请求就存在同域请求和跨域请求。同源策略是浏览器的核心基础安全策略,作用是用来防御非法的攻击.但是我们不能因为要防御非法的攻击,就将所有的跨域问题都拦截掉。

跨域请求:当发起请求的域,与该请求的资源指向的域,不一致

  • 在前端开发当中,经常会用到第三方的服务接口(例如mock server, fake API),随着专业化分工的出现,有很多专业的信息服务提供商为前端开发者提供各类接口,这种情况下就需要跨域请求(大部分用cros方式来解决)
  • 前端后端属于不同的服务,在采用前后端分离这种架构的时候就存在跨域问题(大部分用反向代理的方法来解决)

解决办法:

  • 最简单也最常见:使用jsonp ,即json with padding(内填充),顾名思义,就是把JSON填充到一个盒子里
  • 一劳永逸:直接在服务器端设置跨域资源访问 CORS(Cross-Origin Resource Sharing),设置Request Header头中Access-Control-Allow-Origin为指定可获取数据的域名
  • 简单有效:直接请求一张图片
  • 找”爸爸”:通过修改document.domain来跨子域
  • 哥俩好:通过window.name来跨域接收数据
  • 新石器时代:使用HTML5的window.postMessage方法跨域

3.介绍一下http缓存机制?

缓存发生时机(输入url到看见页面):

  • 1、首先,在浏览器地址栏中输入url
  • 2、浏览器先查看浏览器缓存-系统缓存-路由器缓存,如果缓存中有,会直接在屏幕中显示页面内容。若没有,则跳到第三步操作。
  • 3、在发送http请求前,需要域名解析(DNS解析),解析获取相应的IP地址。
  • 4、浏览器向服务器发起tcp连接,与浏览器建立tcp三次握手。
  • 5、握手成功后,浏览器向服务器发送http请求,请求数据包。
  • 6、服务器处理收到的请求,将数据返回至浏览器
  • 7、浏览器收到HTTP响应
  • 8、读取页面内容,浏览器渲染,解析html源码
  • 9、生成Dom树、解析css样式、js交互
  • 10、客户端和服务器交互
  • 11、ajax查询

Web 缓存:大致可以分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN 缓存)、浏览器缓存。浏览器缓存包含很多内容: HTTP 缓存、indexDB、cookie、localstorage 等等。

http缓存:就是浏览器自己给你的一个功能,一个缓存数据库,夹在服务端和客户端中间,你只需要设置一些参数即可实现:缓存/不缓存/时效内缓存/时效外缓存等(默认存在缓存)。时效内缓存:强制缓存,重点:cache-Control:max-age=xxx。非时效缓存:对比缓存,重点:Etag   Last-Modified/If-Modified-Since。

两种缓存方式:

  • 强制缓存(时效缓存):服务器通知浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。使用Cache-Control (低版本浏览器用的是Expires,了解即可) 
  1. Expires :是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。 

  2. Cache-Control:与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。 它的值有一下6种:

    Cache-Control 是最重要的规则。常见的取值有private、public、no-cache、max-age,no-store,默认为private。
    private 客户端可以缓存
    public 客户端和代理服务器都可缓存(前端的同学,可以认为public和private是一样的)
    max-age=xxx 缓存的内容将在 xxx 秒后失效
    no-cache 需要使用对比缓存来验证缓存数据(后面介绍)
    no-store:           所有内容都不会缓存,强制缓存,对比缓存都不会触发(对于前端开发来说,缓存越多越好,so...基本上和它说886)   
  • 比较缓存(非时效缓存):用的不是时效时间max-age。第一次请求的时候,返回给客户端数据和缓存的信息,也就是一个特定的缓存标识,客户端把这个缓存标识放到缓存数据库。再次请求时,客户端先把缓存标识也一起发给服务端,进行对比。客户端将备份的缓存标识Etag和Last-Modified发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。分为两种缓存标识:Etag 、Last-Modified/If-Modified-Since。对比缓存标识生效不生效时,状态码200,服务端返回body和header;在对比缓存标识生效时,状态码为304,并且报文大小和请求时间大大减少。原因是,服务端在进行标识比较后,只返回header部分,通过状态码通知客户端使用缓存,不再需要将报文主体部分返回给客户端。
  1. Etag(唯一标识,优先级高于Last-Modified / If-Modified-Since):服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。
  2. Last-Modified: 服务器在响应请求时,告诉浏览器资源的最后修改时间,优先级没有Etag高。
  3. If-Modified-Since: 返回给客户端最后这个资源的修改时间,优先级没有Etag高。再次请求服务器时,通过此字段通知服务器上次请求时,服务器返回的资源最后修改时间。 服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。 若资源的最后修改时间大于If-Modified-Since,说明资源有被改动过,则响应整片资源内容,返回状态码200; 若资源的最后修改时间小于或等于If-Modified-Since,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。
  4. If-None-Match: 再次请求服务器时,通过此字段通知服务器客户段缓存数据的唯一标识。 服务器收到请求后发现有头If-None-Match 则与被请求资源的唯一标识进行比对, 不同,说明资源又被改动过,则响应整片资源内容,返回状态码200; 相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache。

 

总结:

强制缓存的优先级更高,如果没失效,就直接用缓存数据库里的东西。如果时间已经失效了,就看用的是哪种标识(Etag服务端生成的唯一标识,还是last-modified资源最后修改时间标识)返回304就用缓存里的,返回200就返回body和新的header。一般来说,无论如何都会协商缓存,浏览器必备的缓存不可能没有

补充:

HTTP报文:浏览器和服务器间通信时发送及响应的数据块。 
浏览器向服务器请求数据,发送请求(request)报文;服务器向浏览器返回数据,返回响应(response)报文。 
报文信息主要分为两部分 

  1. 包含属性的首部(header)————————–附加信息(cookie,缓存信息等)与缓存相关的规则信息,均包含在header中 
  2. 包含数据的主体部分(body)———————–HTTP请求真正想要传输的部分

我做的项目:

//启动文件里

  res.setHeader("Cache-Control", "no-store");//用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。

//log in配置里

  res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');//使用比较缓存

4.介绍一些IO模型?

阻塞IO、非阻塞IO、多路复用IO、信号驱动IO以及异步IO。

  1. 阻塞IO:最传统的一种IO模型,即在读写数据过程中会发生阻塞现象。当用户线程发出IO请求之后,操作系统内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。
  2. 非阻塞IO:当用户线程发起一个read操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。所以事实上,在非阻塞IO模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞IO不会交出CPU,而会一直占用CPU。但是对于非阻塞IO就有一个非常严重的问题,在while循环中需要不断地去轮询内核数据是否就绪,这样会导致CPU占用率非常高,因此一般情况下很少使用while循环这种方式来读取数据。
    //伪代码
    while(true){
    new MyThread(socket)
    }
    class MyThread{
    data = socket.read();
    if(data!= error){
    //处理数据
    break;
    }
    
  3. 多路复用IO:多路复用IO模型是目前使用得比较多的模型。在多路复用IO模型中,会有一个线程不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。在Java NIO中,是通过selector.select()去查询每个通道是否有到达事件,如果没有事件,则一直阻塞在那里,因此这种方式会导致用户线程的阻塞。也许有朋友会说,我可以采用 多线程+ 阻塞IO 达到类似的效果,但是由于在多线程 + 阻塞IO 中,每个socket对应一个线程,这样会造成很大的资源占用,并且尤其是对于长连接来说,线程的资源一直不会释放,如果后面陆续有很多连接的话,就会造成性能上的瓶颈。而多路复用IO模式,通过一个线程就可以管理多个socket,只有当socket真正有读写事件发生才会占用资源来进行实际的读写操作。因此,多路复用IO比较适合连接数比较多的情况。另外多路复用IO为何比非阻塞IO模型的效率高是因为在非阻塞IO中,不断地询问socket状态时通过用户线程去进行的,而在多路复用IO中,轮询每个socket状态是内核在进行的,这个效率要比用户线程要高的多。不过要注意的是,多路复用IO模型是通过轮询的方式来检测是否有事件到达,并且对到达的事件逐一进行响应。因此对于多路复用IO模型来说,一旦事件响应体很大,那么就会导致后续的事件迟迟得不到处理,并且会影响新的事件轮询。
  4. 信号驱动IO:当用户线程发起一个IO请求操作,会给对应的socket注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用IO读写操作来进行实际的IO请求操作。
  5. 异步IO:是最理想的IO模型,在异步IO模型中,当用户线程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从内核的角度,当它受到一个asynchronous read之后,它会立刻返回,说明read请求已经成功发起了,因此不会对用户线程产生任何block。然后,内核会等待数据准备完成,然后将数据拷贝到用户线程,当这一切都完成之后,内核会给用户线程发送一个信号,告诉它read操作完成了。也就说用户线程完全不需要实际的整个IO操作是如何进行的,只需要先发起一个请求,当接收内核返回的成功信号时表示IO操作已经完成,可以直接去使用数据了。也就说在异步IO模型中,IO操作的两个阶段都不会阻塞用户线程,这两个阶段都是由内核自动完成,然后发送一个信号告知用户线程操作已完成。用户线程中不需要再次调用IO函数进行具体的读写。这点是和信号驱动模型有所不同的在信号驱动模型中,当用户线程接收到信号表示数据已经就绪,然后需要用户线程调用IO函数进行实际的读写操作;而在异步IO模型中,收到信号表示IO操作已经完成,不需要再在用户线程中调用iO函数进行实际的读写操作。注意,异步IO是需要操作系统的底层支持,因为无论是多路复用IO还是信号驱动模型,IO操作的第2个阶段都会引起用户线程阻塞,也就是内核进行数据拷贝的过程都会让用户线程阻塞。

5.了解Node模型吗?

Node.js 采用事件驱动异步 I/O 的方式,实现了一个单线程、高并发的 JavaScript 运行时环境。

6.了解mysql吗?了解sql索引吗?数据库里数据量很大,如何快速搜索。

查询效率慢的原因:

1:没有加索引或者索引失效

where条件使用如下语句会索引失效:null、!=、<>、or连接、in(非要使用,可用关键字exist替代)和not in、'%abc%';

使用参数:num=@num、表达式操作:where num/2=100、函数操作:where substring(name,1,3)=‘abc’-name;

2:查询的数据量过大,返回不必要的行和列

只查询有用的字段,不要用*查询出所有字段。用具体的字段列表代替“*”,不要返回用不到的任何字段。

采用多线程多次查询。如果查询条件是某段时间之类的范围条件,可以把时间条件切分,多次查询结果合并。

3:锁或者死锁

4: I/O吞吐量小,形成瓶颈效应。

5:内存不足。

少造对象,对象只在需要使用时创建,不要在整个上下文传递。

及时清理jvm内存。

6:网络速度慢。 

SQL优化方法

1:如果索引是复合索引,必须使用该索引的第一个字段作为条件才能保证系统使用该索引,否则索引不会被引用,并且应尽可能的让字段顺序与索引顺序一致。

2:索引并不是越多越好,一个表索引最好不要超过6个。索引固然可以提高select效率,但是也降低了insert效率和update效率,因为insert和update会使索引重建,所以怎么建索引需要慎重考虑。

3:建表的一些优化:

尽量使用数字型字段,若数据只含有数值信息尽量不要设计成字符型,这会降低查询和连接的性能,并会增加存储开销。因为引擎在处理查询和连接时会逐个比较字符串中每个字符,而对于数字型而言只需比较一次就够了。
尽量使用varchar/nvarchar代替char/nchar,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高一些。
4:尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。(游标是很老的功能了,几乎废弃了。)

5:并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段 sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

6:尽量避免大事务操作,提高系统并发能力。

注意事项:

1:使用like时,一定要记得判空

... where  name like ‘%’.变量名.'%';    (变量值是从外面传进来的)

如果:变量是空,就变成如下sql

...where name like '%%';      --   这个条件造成的后果就是 ‘选出全部数据 or 更新全部数据 or 删除全部数据’ 相当于没有写条件,出现后是相当严重的问题。

2:like 配合 通配符:%和_ 的使用

通配符的分类:
%百分号通配符: 表示任何字符出现任意次数**(可以是0次)**.
_下划线通配符:表示只能匹配单个字符,不能多也不能少,就是一个字符.

like操作符:
LIKE作用是指示mysql后面的搜索模式是利用通配符而不是直接相等匹配进行比较.
注意: 如果在使用like操作符时,后面的没有使用通用匹配符效果是和=一致的,SELECT * FROM products WHERe products.prod_name like '1000';只能匹配的结果为1000,而不能匹配像JetPack 1000这样的结果.

1)%通配符使用:
匹配以"yves"开头的记录:(包括记录"yves")
SELECt * FROM products WHERe products.prod_name like 'yves%';

匹配包含"yves"的记录(包括记录"yves")
SELECt * FROM products WHERe products.prod_name like '%yves%';

匹配以"yves"结尾的记录(包括记录"yves",不包括记录"yves ",也就是yves后面有空格的记录,这里需要注意)
SELECt * FROM products WHERe products.prod_name like '%yves';

2)_通配符使用:
SELECt * FROM products WHERe products.prod_name like '_yves';
匹配结果为: 像"yyves"这样记录.

SELECt * FROM products WHERe products.prod_name like 'yves__';
匹配结果为: 像"yvesHe"这样的记录.(一个下划线只能匹配一个字符,不能多也不能少)

其他操作:

 insert into tb (...) values(...),(...)...; 要比 insert into tb (...) values (...);insert into tb (...) values (...);...方式批量插入效率高 【原因】:这里第二种SQL执行效率高的主要原因是合并后日志量(MySQL的binlog和innodb的事务让日志) 减少了,降低日志刷盘的数据量和频率,从而提高效率。通过合并SQL语句,同时也能减少SQL语句解析的次数,减少网络传输的IO。

7.了解进程和线程吗?CPU处理的基本单位是什么?

进程:程序的一次执行过程,是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,每一个进程都有一个自己的地址空间,至少有 5 种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。

线程:CPU调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

联系:进程是线程的容器。线程是进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

区别:根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位。在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)。内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源。包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。

8.介绍一下CPU处理的算法?

待更

9.进程死锁是什么?

死锁定义:死锁就是一个进程集合中的多个进程因为竞争资源,而造成的互相等待现象。如:A和B吃饺子,A拿着酱油,B拿着醋,A想要醋,B想要酱油,结果二者死等吃不上饺子。

死锁原因:系统资源不足;多个进程的推进顺序不合理;资源分配不当

死锁的必要条件:

(1)互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。

(2)请求与保持条件(Holdand wait):已经得到资源的进程可以再次申请新的资源。

(3)非剥夺条件(Nopre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。

(4)循环等待条件(Circular wait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。

处理死锁的方法有四种:1) 预防死锁    2) 避免死锁    3)检测和解除死锁

预防死锁:破坏四个必要条件之一即可

①破坏互斥条件:让资源允许共享,如SPOOLing技术就可以允许若干个进程同时产生打印数据,

缺点: SPOOLing的技术并不适用于所有的资源,如进程表等,所以破坏资源的互斥性是比较困难的,该方法并不是很好

②破坏请求和保持条件:资源一次性分配。

缺点:采取这种机制,那么进程在执行过程中就不再申请资源了,但这种方法的效率极低,资源无法得到充分的利用。

③破坏不可剥夺条件:有两种方法,一种是当其申请的资源得不到满足时,也必须放弃其原先占有的资源;另一种方法是只适用于申请资源的进程优先级比占有该资源的进程优先级高时,如果一个进程申请的资源被其它进程占用,而申请进程的优先级较高,那么它可以强迫占有资源的进程放弃。这种方法一般适用于处理机和存储资源。

④破坏循环等待条件:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(如:哲学家进餐问题)

避免死锁的方法有两种:1) 资源按序分配   2) 银行家算法。

解除死锁的方法有两种:1) 资源剥夺法   2) 撤消进程法    3)进程回退法

10.给你一个网站的url,请写出这个url内所有url以及通过这些url之后跳转的所有url中不重复的结果?

当时答的用一个树结构,但是还是不会做

11.上传文件和点击一个按钮的content type的区别?http传输协议的区别?

content-type:

一般是指网页中存在的 Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些 PHP 网页点击的结果却是下载一个文件或一张图片的原因。标头告诉客户端实际返回的内容的内容类型。是Http的实体首部字段,用于说明请求或返回的消息主体是用何种方式编码,在request header和response header里都存在。

常见的类型:

text/(plain、 css、html、xml)                               (文本、、 css、html、xml)类型
application/(x-javascript、json、xml、octet-stream)            (js、json、xml、二进制流数据)类型
image/png jpg gif      image/*    

上传excel文件: .xls     application/vnd.ms-excel

12.算法题:输出一个 int 型数组{1,2,5,-7,8,-10}使得和最大的连续子数组

待更

总结:

这次准备的主要是js知识,没想到字节的面试很偏底层的基础,都没复习到。。。算法题也没刷题,做了半小时,没能做出来。。。感觉比前段时间面试的蚂蚁金服难多了。。。

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服