七、React数据流
八、为什么虚拟DOM会提高性能 www.zhihu.com/question/29… 虚拟DOM相当于在js和真实dom中间加了一个缓存,利用dom diff算法避免了没有必要的doom操作,从而提高性能 具体实现步骤: ·用JavaScript对象结构表示DOM树的结构;然后用这个树构建一个真正的DOM树,插到文档中 ·当状态变更的时候,重新构造一棵树的对象树,然后用新的树和旧的树进行对比,记录两棵树差异 ·把2所记录的差异应用到步骤1所构建的真正的DOM树上,试图就更新了。
九、diff算法 1.把树形结构按照层级分解,只比较同级元素 2.给列表结构的每个单元添加key属性,方便比较。在实际代码中,会对新旧两棵树进行一个深度优先的遍历,这样每个节点都会有一个标记 3.在深度优先遍历的时候,每遍历到一个节点就把该节点和新的树进行对比。如果有差异的话就记录到一个对象里面 Vritual DOM 算法主要实现上面步骤的三个函数:element, diff, patch。然后就可以实际的进行使用 react只会匹配相同的class的component(这里的class指的是组件的名字) 合并操作,条用component的setState方法的时候,React将其标记为dirty.到每一个时间循环借宿,React检查所有标记dirty的component重新绘制 4.选择性子树渲染。可以重写shouldComponentUpdate提高diff的性能
十、super
十一、简述下flux的思想 flux的最大特点,就是数据的‘单向流动’ 1.用户访问View 2.View发出用户的Action 3.Dispatcher收到Action,要求state进行相应的更新 4.store更新后,发出一个‘change’事件后,更新页面
十二、reac性能优化是哪个周期函 shouldComponentUpdate 这个方法用来判断是否需要调用render方法重新描绘dom.因为dom的描绘非常消耗性能, 如果我们在shouldComponentUpdate方法中能够写出更优化的dom diff算法,可以极大的提高性能
十三、react怎么划分业务组件和技术组件 根据组件的职责通常把组件分为UI组件和容器组件 UI组件负责UI的呈现,容器组件负责管理数据和逻辑 两者通过React-redux提供connect方法联系起来
十四、setState setState通过一个队列机制实现state更新,当执行setState时,会将需要更新的state很后放入状态队列 而不会立即更新this.state,队列机制可以高效地批量更新state。如果不通过setState而直接修改this.state的值 那么该state将不会被放入状态队列中。当下次调用setState并对状态队列进行合并时,就会忽略之前修改的state,造成不可预知的错误
同时,也利用了队列机制实现了setState的异步更新,避免了频繁的重复更新state
同步更新state:
setState 函数并不会阻塞等待状态更新完毕,因此 setNetworkActivityIndicatorVisible 有可能先于数据渲染完毕就执行。第二个参数是一个回调函数,在setState的异步操作结束并且组件已经重新渲染的时候执行
也就是说,我们可以通过这个回调来拿到更新的state的值,实现代码的同步
例子:componentDidMount() {
fetch('https://test.com')
.then((res) => res.json())
.then(
(data) => { this.setState({ data:data });
StatusBar.setNetworkActivityIndicatorVisible(false);
}
性能优化
一、webpack打包文件体积过大?(最终打包为一个js文件) 1.异步加载模块 2.提取第三库 3.代码压缩 4.去除不必要的插件
如何优化webpack构建的性能 一、减少代码体积 1.使用CommonsChunksPlugin 提取多个chunk之间的通用模块,减少总体代码体积 2.把部分依赖转移到CDN上,避免每次编译过程都由Webpack处理 3.对一些组件库采用按需加载,避免无用的代码 二、减少目录检索范围 ·在使用loader的时候,通过制定exclude和include选项,减少loader遍历的目录范围,从而加快webpack编译速度
三、减少检索路经:resolve.alias可以配置webpack模块解析的别名,对于比较深的解析路经,可以对其配置alias
二、我们把开发中的所有资源(图片,js、css文件)都看成模块,通过loader和plugins来对资源进行处理,打包成符合生产环节部署的前端资源。
三、移动端的性能优化 1、首屏加载和按需加载,懒加载 2、资源预加载 3、图片压缩处理,使用base64内嵌图片 4、合理缓存dom对象 5、使用touchstart代替click(click 300毫秒的延迟) 6、利用transform:translateZ(0),开启硬件GUP加速 7、不滥用web字体,不滥用float(布局计算消耗性能),减少font-size声明 8、使用viewport固定屏幕渲染,加速页面渲染内容 9、尽量使用事件代理,避免直接事件绑定
四、Vue的SPA 如何优化加载速度 1.减少入口文件体积 2.静态资源本地缓存 3.开启Gzip压缩 4.使用SSR,nuxt.js
五、移动端300ms延迟 由来:300毫米延迟解决的是双击缩放。双击缩放,手指在屏幕快速点击两次。safari浏览器就会将网页缩放值原始比例。 由于用户可以双击缩放或者是滚动的操作,当用户点击屏幕一次之后,浏览器并不会判断用户确实要打开至这个链接,还是想要进行双击操作 因次,safair浏览器就会等待300ms,用来判断用户是否在次点击了屏幕 解决方案:1.禁用缩放,设置meta标签 user-scalable=no 2.fastclick.js 原理:FastClick的实现原理是在检查到touchend事件的时候,会通过dom自定义事件立即 发出click事件,并把浏览器在300ms之后真正的click事件阻止掉 fastclick.js还可以解决穿透问题
六、页面的重构;在不改变外部行为的前提下,简化结构、添加可读性
服务器端
一、状态码:
2XX(成功处理了请求状态)
200 服务器已经成功处理请求,并提供了请求的网页
201 用户新建或修改数据成功
202 一个请求已经进入后台
204 用户删除成功
3XX(每次请求使用的重定向不要超过5次)
304 网页上次请求没有更新,节省带宽和开销
4XX(表示请求可能出错,妨碍了服务器的处理)
400 服务器不理解请求的语法
401 用户没有权限(用户名,密码输入错误)
403 用户得到授权(401相反),但是访问被禁止
404 服务器找不到请求的网页,
5XX(表示服务器在处理请求的时候发生内部错误)
500 服务器遇到错误,无法完成请求
503 服务器目前无法使用(超载或停机维护)
二、304的缓存原理(添加Etag标签.last-modified) 304 网页上次请求没有更新,节省带宽和开销 1.服务器首先产生Etag,服务器可在稍后使用它来判断页面是否被修改。本质上,客户端通过该记号传回服务器要求服务器验证(客户端)缓存) 2.304是 HTTP的状态码,服务器用来标识这个文件没有被修改,不返回内容,浏览器接受到这个状态码会去去找浏览器缓存的文件 3.流程:客户端请求一个页面A。服务器返回页面A,并在A上加一个Tage客服端渲染该页面,并把Tage也存储在缓存中。客户端再次请求页面A 并将上次请求的资源和ETage一起传递给服务器。服务器检查Tage.并且判断出该页面自上次客户端请求之后未被修改。直接返回304
last-modified: 客服端请求资源,同时有一个last-modified的属性标记此文件在服务器最后修改的时间
客服端第二次请求此url时,根据http协议。浏览器会向服务器发送一个If-Modified-Since报头,
询问该事件之后文件是否被修改,没修改返回304
有了Last-Modified,为什么还要用ETag?
1、因为如果在一秒钟之内对一个文件进行两次更改,Last-Modified就会不正确(Last—Modified不能识别秒单位的修改)
2、某些服务器不能精确的得到文件的最后修改时间
3、一些文件也行会周期新的更改,但是他的内容并不改变(仅仅改变修改的事件),这个时候我们并不希望客户端认为文件被修改,而重新Get
ETag,为什么还要用Last-Modified?
1、两者互补,ETag的判断的缺陷,比如一些图片等静态文件的修改
2、如果每次扫描内容都生成ETag比较,显然要比直接比较修改时间慢的多。
ETag是被请求变量的实体值(文件的索引节,大小和最后修改的时间的Hash值)
1、ETag的值服务器端对文件的索引节,大小和最后的修改的事件进行Hash后得到的。
三、get/post的区别 1.get数据是存放在url之后,以?分割url和传输数据,参数之间以&相连; post方法是把提交的数据放在http包的Body中 2.get提交的数据大小有限制,(因为浏览器对url的长度有限制),post的方法提交的数据没有限制 3.get需要request.queryString来获取变量的值,而post方式通过request.from来获取变量的值 4.get的方法提交数据,会带来安全问题,比如登录一个页面,通过get的方式提交数据,用户名和密码就会出现在url上
四、http协议的理解 1.超文本的传输协议,是用于从万维网服务器超文本传输到本地资源的传输协议 2.基于TCP/IP通信协议来传递数据(HTML,图片资源) 3.基于运用层的面向对象的协议,由于其简洁、快速的方法、适用于分布式超媒体信息系统 4.http请求信息request: 请求行(request line)、请求头部(header),空行和请求数据四部分构成
请求行,用来说明请求类型,要访问的资源以及所使用的HTTP版本.
请求头部,用来说明服务器要使用的附加信息
空行,请求头部后面的空行是必须的
请求数据也叫主体,可以添加任意的其他数据。
5.http相应信息Response
状态行、消息报头、空行和响应正文
状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成
消息报头,用来说明客户端要使用的一些附加信息
空行,消息报头后面的空行是必须的
响应正文,服务器返回给客户端的文本信息。
五、http和https https:是以安全为目标的HTTP通道,简单讲是HTTP的安全版本,通过SSL加密 http:超文本传输协议。是一个客服端和服务器端请求和应答的标准(tcp),使浏览器更加高效,使网络传输减少
五、http1.0 1.1 2.0的区别 长连接:HTTP1.0需要使用keep-alive参数来告知服务器建立一个长连接,而HTP1.1默认支持长连接 节约宽带:HTTP1.1支持只发送一个header信息(不带任何body信息) host域(设置虚拟站点,也就是说,web server上的多个虚拟站点可以共享同一个ip端口):HTTP1.0没有host域
1.http2采用的二进制文本传输数据,而非http1文本格式,二进制在协议的解析和扩展更好
2.数据压缩:对信息头采用了HPACK进行压缩传输,节省了信息头带来的网络流量
3.多路复用:一个连接可以并发处理多个请求
4.服务器推送:我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源
七、web缓存 1.web缓存就是存在于客户端与服务器之间的一个副本、当你第一个发出请求后,缓存根据请求保存输出内容的副本 2.缓存的好处 (1)减少不必要的请求 (2)降低服务器的压力,减少服务器的消耗 (3)降低网络延迟,加快页面打开速度(直接读取浏览器的数据)
八、常见的web安全及防护原理 1.sql注入原理:通郭sql命令插入到web表单递交或者输入活命,达到欺骗服务器执行的恶意sql命令 防范:1.对用户输入进行校验 2.不适用动态拼接sql 2.XSS(跨站脚本攻击):往web页面插入恶意的html标签或者js代码。 举例子:在论坛放置一个看是安全的链接,窃取cookie中的用户信息 防范:1.尽量采用post而不使用get提交表单 2.避免cookie中泄漏用户的隐式 3.CSRF(跨站请求伪装):通过伪装来自受信任用户的请求 举例子:黄轶老师的webapp音乐请求数据就是利用CSRF跨站请求伪装来获取QQ音乐的数据 防范:在客服端页面增加伪随机数,通过验证码 XSS和CSRF的区别: 1.XSS是获取信息,不需要提前知道其他用户页面的代码和数据包 2.CSRF代替用户完成指定的动作,需要知道其他页面的代码和数据包
九、CDN(内容分发网络) 1.尽可能的避开互联网有可能影响数据传输速度和稳定性的瓶颈和环节。使内容传输的更快更稳定。 2.关键技术:内容存储和分发技术中 3.基本原理:广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对的地区或者网络中。当用户访问网络时利用全局负载技术 将用户的访问指向距离最近的缓存服务器,由缓存服务器直接相应用户的请求(全局负载技术)
十、TCP三次握手 (客服端和服务器端都需要确认各自可收发) 客服端发c起请求连接服务器端s确认,服务器端也发起连接确认客服端确认。 第一次握手:客服端发送一个请求连接,服务器端只能确认自己可以接受客服端发送的报文段 第二次握手: 服务端向客服端发送一个链接,确认客服端收到自己发送的报文段 第三次握手: 服务器端确认客服端收到了自己发送的报文段
十一、从输入url到获取页面的完整过程 blog.csdn.net/samjustin1/… 1.查询NDS(域名解析),获取域名对应的IP地址 查询浏览器缓存 2.浏览器与服务器建立tcp链接(三次握手) 3.浏览器向服务器发送http请求(请求和传输数据) 4.服务器接受到这个请求后,根据路经参数,经过后端的一些处理生成html代码返回给浏览器 5.浏览器拿到完整的html页面代码开始解析和渲染,如果遇到外部的css或者js,图片一样的步骤 6.浏览器根据拿到的资源对页面进行渲染,把一个完整的页面呈现出来
十二、浏览器渲染原理及流程 DOM -> CSSOM -> render -> layout -> print 流程:解析html以及构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树 概念:1.构建DOM树: 渲染引擎解析HTML文档,首先将标签转换成DOM树中的DOM node(包括js生成的标签)生成内容树 2.构建渲染树: 解析对应的css样式文件信息(包括js生成的样式和外部的css) 3.布局渲染树:从根节点递归调用,计算每一个元素的大小,位置等。给出每个节点所在的屏幕的精准位置 4.绘制渲染树:遍历渲染树,使用UI后端层来绘制每一个节点
重绘:当盒子的位置、大小以及其他属性,例如颜色、字体大小等到确定下来之后,浏览器便把这些颜色都按照各自的特性绘制一遍,将内容呈现在页面上
触发重绘的条件:改变元素外观属性。如:color,background-color等
重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观
注意:table及其内部元素需要多次计算才能确定好其在渲染树中节点的属性值,比同等元素要多发时间,要尽量避免使用table布局
重排(重构/回流/reflow): 当渲染书中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就是回流。
每个页面都需要一次回流,就是页面第一次渲染的时候
重排一定会影响重绘,但是重绘不一定会影响重排
十三、为什么css放在顶部而js写在后面 1.浏览器预先加载css后,可以不必等待HTML加载完毕就可以渲染页面了 2.其实HTML渲染并不会等到完全加载完在渲染页面,而是一边解析DOM一边渲染。 3.js写在尾部,主要是因为js主要扮演事件处理的功能,一方面很多操作是在页面渲染后才执行的。另一方面可以节省加载时间,使页面能够更加的加载,提高用户的良好体验
但是随着JS技术的发展,JS也开始承担页面渲染的工作。比如我们的UI其实可以分被对待,把渲染页面的js放在前面,时间处理的js放在后面
十四、存储方式与传输方式 1.indexBD: 是h5的本地存储库,把一些数据存储到浏览器中,没网络,浏览器可以从这里读取数据,离线运用。5m 2.Cookie: 通过浏览器记录信息确认用户身份,最大4kb,这也就限制了传输的数据,请求的性能会受到影响 3.Session: 服务器端使用的一种记录客户状态的机制(session_id存在set_cookie发送到客服端,保存为cookie) 4.localStroage: h5的本地存储,数据永久保存在客服端
1、cookie,sessionStorage,localStorage是存放在客户端,session对象数据是存放在服务器上
实际上浏览器和服务器之间仅需传递session id即可,服务器根据session-id找到对应的用户session对象
session存储数据更安全一些,一般存放用户信息,浏览器只适合存储一般的数据
2、cookie数据始终在同源的http请求中携带,在浏览器和服务器来回传递,里面存放着session-id
sessionStorage,localStorage仅在本地保存
3、大小限制区别,cookie数据不超过4kb,localStorage在谷歌浏览中2.6MB
4、数据有效期不同,cookie在设置的(服务器设置)有效期内有效,不管窗口和浏览器关闭
sessionStorage仅在当前浏览器窗口关闭前有效,关闭即销毁(临时存储)
localStorage始终有效
SessionStorage和localStorage区别: 1.sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在用一个会话的页面中才能被访问(也就是说在第一次通信过程中) 并且在会话结束后数据也随之销毁,不是一个持久的本地存储,会话级别的储存 2.localStorage用于持久化的本地存储,除非主动删除数据,否则不会过期
token、cookie、session三者的理解???!!! 1、token就是令牌,比如你授权(登录)一个程序时,他就是个依据,判断你是否已经授权该软件(最好的身份认证,安全性好,且是唯一的) 用户身份的验证方式
2、cookie是写在客户端一个txt文件,里面包括登录信息之类的,这样你下次在登录某个网站,就会自动调用cookie自动登录用户名
服务器生成,发送到浏览器、浏览器保存,下次请求再次发送给服务器(存放着登录信息)
3、session是一类用来客户端和服务器之间保存状态的解决方案,会话完成被销毁(代表的就是服务器和客户端的一次会话过程)
cookie中存放着sessionID,请求会发送这个id。sesion因为request对象而产生。
基于Token的身份验证:(最简单的token: uid用户唯一的身份识别 + time当前事件戳 + sign签名)
1、用户通过用户名和密码发送请求
2、服务器端验证
3、服务器端返回一个带签名的token,给客户端
4、客户端储存token,并且每次用于发送请求
5、服务器验证token并且返回数据
每一次请求都需要token
cookie与session区别
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
session与token区别
1、session认证只是把简单的User的信息存储Session里面,sessionID不可预测,一种认证手段。只存在服务端,不能共享到其他的网站和第三方App
2、token是oAuth Token,提供的是认证和授权,认证针对用户,授权是针对App,目的就是让某APP有权访问某用户的的信息。Token是唯一的,
token不能转移到其他的App,也不能转到其他用户上。(适用于App)
3、session的状态是存在服务器端的,客户端只存在session id, Token状态是存储在客户端的
Cookie的弊端有哪些???(优势:保存客户端数据,分担了服务器存储的负担)
1、数量和长度的限制。每个特定的域名下最多生成20个cookie(chorme和safari没有限制)
2、安全性问题。
设计模式
一、观察者模式:juejin.cn/post/684490… juejin.cn/post/684490… 在软件开发设计中是一个对象(subject),维护一系列依赖他的对象(observer),当任何状态发生改变自动通知他们。强依赖关系 简单理解:数据发生改变时,对应的处理函数就会自动执行。一个Subjet,用来维护Observers,为某些event来通知(notify)观察者
二、发布-订阅者 有一个信息中介,过滤 耦合性低 它定义了一种一对多的关系,可以使多个观察者对象对一个主题对象进行监听,当这个主题对象发生改变时,依赖的所有对象都会被通知到。
两者的区别: 1.观察者模式中,观察者知道Subject ,两者是相关联的,而发发布订阅者只有通过信息代理进行通信 2.在发布订阅模式中,组件式松散耦合的。正好和观察者模式相反。 3.观察者大部分是同步的,比如事件的触发。Subject就会调用观察者的方法。而发布订阅者大多数是异步的() 4.观察者模式需要在单个应用程序地址空间中实现,而发布订阅者更像交叉应用模式。
1004001111 数据结构和算法
一、两个栈实现一个队列,两个队列实现一个栈 www.cnblogs.com/MrListening…
二、红黑树(解决二叉树依次插入多个节点时的线型排列) juejin.cn/post/684490…
三、最小栈的实现(查找最小元素,用两个栈配合栈内元素的下标)juejin.cn/post/684490…
四、十大排序 1.冒泡排序:重复走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把它们交换过来。 实现过程:1.比较相邻的元素。如果第一个比第二个大,就交换他们两个 2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数 3.针对所有的元素重复以上的步骤,除了最后一个 4.重复步骤1-3,直到排序完成。 2.选择排序:首先在未排序序列中找到最小值,放在排序序列的起始位置,然后,在从剩下未排序元素中继续寻找最小值,然后放在与排序序列的末尾 实现过程:
3.插入排序:构建有序序列,对于未排序数据,在已排序序列中冲后向前扫描,找到相应位置并插入
实现过程:1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已排序的元素序列中冲后向前扫描
3.如果该元素(以排序)大于新元素,将元素向后移一位
4.在取出一个元素,比较之前的,直到找到自己合适的位置
4.桶排序:将数据分布到有限数量的桶里,每个桶在分别排序
1.快速排序:快速排序使用分治法把一个串(list)分为两个子串(sub-lists).具体算法实现
实现过程:1.从数组中挑出一个元素,成为一个基准
2.重新排列数组,所有元素比基准小的摆在基准前面,所有元素比基准大的摆在基准后面(相同的可以摆在一边)
这个分区退出之后,该基准就处于数列的中间位置。成为分区操作。
3.递归的把小于基准值的子数列和大于基准值元素的子数列排序
算法实现: function quickSort (arr) {
if (arr.length <= 1) {return arr}
var destIndex = Math.floor(arr.length/2)
var left = [], right = [];
var dest = arr.splice(destIndex,1)[0];
for (var i =0;i<arr.length;i++){
if (arr[i]<dest) {
left.push(arr[i])
} else {
right.push(arr[i]) }
return quickSort(left).concat([dest],quickSort(right)
2.堆排序:利用对这种数据结构所涉及的一种排序算法,堆积是一个近乎完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或大于)它的父节点。
实现过程:1.
五、数组去重 juejin.cn/post/684490… 1.双重循环 2.indexOf 3.数组排序去重 最快你Olong
六、字符串 判断回文字符串:(递归的思想) 1.字符串分隔,倒转,聚合[...obj].reverse().join('') 2.字符串头部和尾部,逐次向中间检测 实现:function isPalindrome(line) { line += ''; for (var i=0,j=line.length-1;i<j;i++,j--) { if (line.chartAt(i) !== line.chartAt(j) { return false }
3.递归
七、二分查找(有序数组的查找) 二分查找可以解决已排序数组的查找问题,即只要数组中包含T(要查找的值),那么通过不断的缩小包含T的数据范围,就可以最终要找到的数 (1) 一开始,数据范围覆盖整个数组。 (2) 将数组的中间项与T进行比较,如果T比数组的中间项小,则到数组的前半部分继续查找,反之,则到数组的后半部分继续查找。 (3) 就这样,每次查找都可以排除一半元素,相当于范围缩小一半。这样反复比较,反复缩小范围,最终会在数组中找到T 代码实现:function binarySearch (data, dest, start, end){ var end = end || data.length-1; var start = start || 0; var m = Math.floor((start+end)/2); if (dest<data[m]){ return binarySearch(data, dest, 0, m-1) } else { return binarySearch(data, dest, m+1, end) }} return false
手写代码
一、动手实现一个bind(原理通过apply,call) 一句话概括:1.bind()返回一个新函数,并不会立即执行。 2.bind的第一个参数将作为他运行时的this,之后的一系列参数将会在传递的实参前传入作为他的参数 3.bind返回函数作为构造函数,就是可以new的,bind时指定的this值就会消失,但传入的参数依然生效 Function.prototype.bind = function (obj, arg) { var arg = Array.prototype.slice.call(arguments, 1); var context = this; var bound = function (newArg) { arg = arg.concat(Array.prototype.slice.call(newArg); return context.apply(obj, arg) } var F = function () {} // 在new一个bind会生成新函数,必须的条件就是要继承原函数的原型,因此用到寄生继承来完成我们的过程 F.prototype = context.prototype; bound.prototype = new F(); return bound; }
二、 AJAX (异步的javascript和xml) ajax的原理:相当于在用户和服务器之间加一个中间层(ajax引擎),使用户操作与服务器响应异步化。 优点:在不刷新整个页面的前提下与服务器通信维护数据。不会导致页面的重载 可以把前端服务器的任务转嫁到客服端来处理,减轻服务器负担,节省宽带 劣势:不支持back。对搜索引擎的支持比较弱;不容易调试 怎么解决呢?通过location.hash值来解决Ajax过程中导致的浏览器前进后退按键失效, 解决以前被人常遇到的重复加载的问题。主要比较前后的hash值,看其是否相等,在判断是否触发ajax function getData(url) { var xhr = new XMLHttpRequest(); // 创建一个对象,创建一个异步调用的对象 xhr.open('get', url, true) // 设置一个http请求,设置请求的方式,url以及验证身份 xhr.send() //发送一个http请求 xhr.onreadystatechange = function () { //设置一个http请求状态的函数 if (xhr.readyState == 4 && xhr.status ==200) { console.log(xhr.responseText) // 获取异步调用返回的数据 } } } Promise(getData(url)).resolve(data => data)
AJAX状态码:0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send方法,正在发送请求
2 - (载入完成呢)send()方法执行完成
3 - (交互)正在解析相应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
三、函数节流(throttle) function throttle (func, wait) { var timeout; var previous = 0; return function () { context = this; args = arguments; if (!timeout) { timeout = setTimeout(() => { timeout = null; func.apply(context,args) }, wait); } } }
}
四、函数防抖(dobounce) function debounce (func, wait) { var timeout; return function() { var context = this; var args = arguments; clearTimeout(timeout); timeout = setTimeout(() => { func.apply(context,args) }, wait); } }
五、实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制
Object.prototype.clone = function() {
var newObject = this.constructor === Array ? [] : {} //对象的深拷贝 获取对应的构造函数 [] 或者 {}
for (let e in this) { //遍历对象的属性 in this[e]
newObject[e] = typeof this[e] === 'object' ? this[e].clone() : this[e] //对象中的属性如果还是对象 那就继续递归 否则就返回基本的数据类型
}
return newObject
}
六、实现一个简单的Promise juejin.cn/post/684490… class Promise { constructor (executor) { // executor里面有两个参数,一个叫resolve(成功),一个叫reject(失败)。 this.status = 'pending', this.value = undefined; this.reason = undefined; // 成功存放的数组 this.onResolvedCallbacks = []; // 失败存放法数组 this.onRejectedCallbacks = []; let resolve = (value) => { if (this.status == 'pending') { this.status = 'resolve'; this.value = value; this.onResolvedCallbacks.forEach(fn => fn()) } }
let reject = (reason) => {
if (this.status == 'pending') {
this.status = 'reject';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
} then (onFullFilled,onRejected) { if (this.status == 'resolved') { onFullFilled(this.value) } if (this.status == 'rejectd') { onRejected(this.reason); } if (this.status == 'pending') { this.onResolvedCallbacks.push(()=>{ onFullFilled(this.value); }) this.onRejectedCallbacks.push(()=> { onRejected(this.reason); }) }
} }
const p = new Promise((resolve, reject) => { setTimeout(() => { resolve('hello world') }, 1000); }) p.then((data) =>{ console.log(data) },(err) =>{ console.log(err); })
七、发布订阅者模式(观察者模式)
var event = {}; // 发布者 event.clientList = [] //发布者的缓存列表
event.listen = function (fn) { // 增加订阅者函数 this.clientList.push(fn) }
event.trigger = function () { // 发布信息 for (var i =0;i<this.clientList.length;i++) { var fn = this.clientList[i]; fn.apply(this, arguments); } }
event.listen (function(time) { console.log('正式上班时间为:' +time) }) event.trigger ('2018/7')
八、手动写一个node服务器 const http = require('http'); const fs = require('fs'); const server = http.createServer((req,res) => { if (reu.url == '/') { const indexFile = fs.createReadStream('./index.html') req.writeHead(200,{'context-Type':'text/html;charset = utf8}) indexFile.pipe(res) } server.listen(8080)