记录一种解题思路……
1 | let str = "aaafdaewrebdafdasfdsafdsafb"; |
记录一种解题思路……
1 | let str = "aaafdaewrebdafdasfdsafdsafb"; |
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
当前Web应用中较常见的一种持续通信方式,通常采取 setInterval 或者 setTimeout 实现。例如如果我们想要定时获取并刷新页面上的数据,可以结合Ajax写出如下实现:
1 | setInterval(function() { |
上面的程序会每隔10秒向服务器请求一次数据,并在数据到达后存储。这个实现方法通常可以满足简单的需求,然而同时也存在着很大的缺陷:在网络情况不稳定的情况下,服务器从接收请求、发送请求到客户端接收请求的总时间有可能超过10秒,而请求是以10秒间隔发送的,这样会导致接收的数据到达先后顺序与发送顺序不一致。于是出现了采用 setTimeout 的轮询方式:
1 | function poll() { |
程序首先设置10秒后发起请求,当数据返回后再隔10秒发起第二次请求,以此类推。这样的话虽然无法保证两次请求之间的时间间隔为固定值,但是可以保证到达数据的顺序。
程序在每次请求时都会新建一个HTTP请求,然而并不是每次都能返回所需的新数据。当同时发起的请求达到一定数目时,会对服务器造成较大负担。
客户端发送一个request后,服务器拿到这个连接,如果有消息,才返回response给客户端。没有消息,就一直不返回response。之后客户端再次发送request, 重复上次的动作。
http协议的特点是服务器不能主动联系客户端,只能由客户端发起。它的被动性预示了在完成双向通信时需要不停的连接或连接一直打开,这就需要服务器快速的处理速度或高并发的能力,是非常消耗资源的。
WebSocket是HTML5的一个新协议,它允许服务端向客户端传递信息,实现浏览器和客户端双工通信
因为 HTTP 协议有一个缺陷:通信只能由客户端发起。 举例来说,我们想了解今天的天气,只能是客户端向服务器发出请求,服务器返回查询结果。HTTP 协议做不到服务器主动向客户端推送信息。这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。我们只能使用”轮询”:每隔一段时候,就发出一个询问,轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。因此,工程师们一直在思考,有没有更好的方法。WebSocket 就是这样发明的。
服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
跨平台的WebSocket通信库,具有前后端一致的API,可以触发和响应自定义的事件。socket.io最核心的两个api就是emit 和 on了 ,服务端和客户端都有这两个api。通过 emit 和 on可以实现服务器与客户端之间的双向通信。
1 | var app = require('express')(); |
1 | <body> |
对于搭建大型项目前后端分离是必须的,前后端分离的好处不用多说。前端工作一个重要的技能就是对接后台给的接口,从最初的Ajax,到目前比较火的fetch和axios,因为axios可以拦截请求和响应,转换请求数据和响应数据,并对响应回来的内容自动转换为json类型的数据等优势,个人比较喜欢使用axios。
Ajax是一种可以在浏览器和服务器之间使用异步数据传输(HTTP请求)的技术。使用它可以让页面请求少量的数据,而不用刷新整个页面。而传统的页面(不使用Ajax)要刷新部分内容,必须重载整个网页页面。它基于的是XMLHttpRequest(XHR)。这是一个比较粗糙的API,不符合关注分离的设计原则(Separation of Concerns),配置和使用都不是那么友好。
fetch是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。提供了一个 JavaScript接口,用于访问和操纵HTTP管道的部分,例如请求和响应。它还提供了一个全局fetch()
方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。fetch不是ajax的进一步封装,而是原生js。
fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。
旧版本的浏览器不支持Promise,需要使用polyfill es6-promise。
1 | function handleResponse(res: Response): Promise<any> { |
优点:
缺点:
axios是一个基于promise的HTTP库,支持promise的所有API。
axios也是对原生XHR的一种封装,不过是Promise实现版本,用于浏览器和node.js的http客户端
例子:
1 | axios |
优缺点:
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:
浅拷贝:复制变量的地址,所有地址对象都指向一个数据,而且所有地址对象都能修改这个数据。
深拷贝:复制变量的值。对于非基本类型的变量,可以通过递归至基本类型后,再复制。数组中可以使用slice和concat方法来进行深拷贝。
递归是什么? 如果一个函数在内部调用自身本身,这个函数就是递归函数。
1 | //使用递归的方式实现数组、对象的深拷贝 |
1 | //通过js的内置对象JSON来进行数组对象的深拷贝 |
JSON对象实现深拷贝的一些问题,无法实现对对象中方法的深拷贝
1 | var array = [1,2,3,4]; |
1 | 当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。1 |
1 | lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝 |
最近开发的时候遇到了数组拷贝的问题,数组a是原数组,数组b是拷贝的数组,当操作数组b的时候,数组a也发生了变化, 然后想到了数组深拷贝和浅拷贝。
JS中变量分基本数据类型和引用数据类型。
基本数据: String,Number,Boolean,Undefined,Null
引用数据类型:Object,Function,Array等。
栈(Stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。
如果是基础类型,那栈中存的是数据本身。
如果是对象类型,那栈中存的是堆中对象的引用。
栈内存的运行效率比堆内存高,栈内存的空间比堆内存小。
基本数据的值和地址都存在栈内存中。
引用类型的值存放在栈内存中,引用类型的地址存放在堆内存中。
浅拷贝:复制变量的地址,所有地址对象都指向一个数据,而且所有地址对象都能修改这个数据。
深拷贝:复制变量的值。对于非基本类型的变量,则递归至基本类型变量后,再复制。数组中可以使用slice和concat方法来进行深拷贝。
DOM级别一共可以分为4个级别:DOM0级,DOM1级,DOM2级和DOM3级,
而DOM事件分为3个级别:DOM0级事件处理,DOM2级事件处理和DOM3级事件处理。
事件:指可以被 JavaScript 侦测到的行为。即鼠标点击、页面或图像载入、鼠标悬浮于页面的某个热点之上、在表单中选取输入框、确认表单、键盘按键等操作。事件通常与函数配合使用,当事件发生时函数才会执行。
事件名称:click/mouseover/blur(“不带on”)
事件处理程序(事件侦听器:**addEventListener
**):响应某个事件的函数 。
事件处理程序函数名称:onclick/onmouseove/onblur
事件流:指从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。
IE事件流是事件冒泡,Netscape的事件流是事件捕获。
“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标阶段接收到事件被触发。最后的阶段是冒泡阶段可以在这个阶段对事件做出响应。
冒泡: IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。即从下到上,从目标触发的元素逐级向上传播,直到window对象。
给子级加 event.stopPropagation( )
在事件处理函数中返回 false
但是这两种方式是有区别的。return false
不仅阻止了事件往上冒泡,而且阻止了事件本身(默认事件)。event.stopPropagation()
则只阻止事件往上冒泡,不阻止事件本身。
event.target==event.currentTarget,让触发事件的元素等于绑定事件的元素,也可以阻止事件冒泡;
阻止默认事件:event.preventDefault( )
捕获: Netscape团队提出了另一种事件流叫做事件捕获。事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件,事件捕获的用意在于在事件到达预定目标之前捕获它。
通过设置addEventListener
的第三个参数可以决定事件是否在捕获阶段触发。
stopPropagation()方法既可以阻止事件冒泡,也可以阻止事件捕获,也可以阻止处于目标阶段。
使用DOM3级新增事件stopImmediatePropagation()方法来阻止事件捕获,另外此方法还可以阻止事件冒泡。
1 | element.addEventListener(event, function, useCapture) |
1 | typeof {} // object |
原理 因为A instanceof B 可以判断A是不是B的实例,返回一个布尔值,由构造类型判断出数据类型
1 | console.log(arr instanceof Array ); // true |
1 | Object.prototype.toString.call(); |
1 | console.log('数据类型判断' - constructor); |
对于前后端分离的项目,前后端的优化都是很重要的。后台优化服务器,排查SQL命令等。前后台优化都是相辅相成的,后台的响应速度快,前端的页面加载速度也要快速,用户体验才能更好。
优化HTTP请求数,由于用户浏览的往往是局部网页,所以只加载用户可视范围内的资源,就会减少一些不必要的请求,也会减少浏览器加载资源的消耗。页面优化主要包括网络加载类、页面渲染类、CSS优化类、JavaScript执行类、缓存类、图片类、架构协议类等几类;
图片延迟加载
延长加载也称懒加载。我们常用的是react-lazyload(Lazyload your Components, Images or anything matters the performance.) 来进行图片的预加载和延迟加载处理。前面有懒加载和预加载的文章。
定义图片大小限制
加载的单张图片一般建议不超过30KB,避免大图片加载时间长而阻塞页面其他资源的下载,因此推荐10KB以内,如果用户上传的图片过大,建议设置告警系统,帮助我们观察了解整个网站的图片流量情况,做出进一步的改善。
预加载资源(图片和数据请求)
但有一些需求是希望尽量少出现延迟加载带来的“等待”过程,这时就可以预加载资源。
资源合并
可以把多个脚本合并到一个js文件内,然后统一引用它就能减少http请求。
通用的CSS样式可以合并到一个文件里。
通用的组件和方法可以提取出来。
引用优化
引用css放在
内,引用js放在结束标签前。css加载是异步的,更早的加载出样式就能更早呈现出页面。
js放在尾部,防止浏览器加载js而阻塞页面,造成页面“白屏”现象。
单独域名存放资源
如果有条件的话,我们还可以启用额外的服务器,域名来存放资源
这样能减少主域名的HTTP请求数,让主服务器更快响应请求
还能减少主域名的cookie请求
离线存储
在移动端应用的比较多
它和缓存不同,它设置好之后,离线也能访问,无论用户刷新或者新窗口,链接等等
本地存储localStorage
本地存储数据一直是网页端的弱项,在没有HTML5的localStorage前,用cookie可以保存一点数据
但付出的代价很大,cookie能保存的数据很少,并且它会伴随着每一次请求一起发送
localStorage就好多了,默认5MB的大小,除非用户手动清除,否则一直不过期,就连IE8浏览器都支持
这里要注意,localStorage和cookie一样受到跨域的限制
可以使用domain控制
CSS3替换js动画
在js中,我们实现动画,就是利用定时器循环改变dom元素的属性来达到动画效果
但是许多属性更改之后会造成浏览器重绘,增加性能消耗
css3在动画效率上面有增强,浏览器会单独处理css3动画,不占用js主线程,还可以硬件加速
apply()、call()和bind()方法都是Function.prototype对象中的方法,而所有的函数都是Function的实例。这三个方法的用法非常相似,将函数绑定到上下文中,即用来改变函数中this的指向。
1 | function Person(name){ |
apply和call都是直接执行函数调用。
bind是绑定,执行需要再次调用。
apply和call的区别是从第二个参数开始,apply接受数组作为参数,而call是接受逗号分隔的无限多个参数列表。
1 | //含有length属性的对象 |
利用call和apply做继承
1 | function Animal(name){ |
求数组中的最大值和最小值
1 | let arr = [1,2,3,89,46] |
数组的追加
1 | let arr1 = [1,2,3] |
总结
三者都可以改变函数的this对象指向。
三者第一个参数都是this要指向的对象,如果如果没有这个参数,默认指向全局window。
三者都可以传参,但是apply是数组,而call是有顺序的传入。
bind 是返回对应函数,便于稍后调用。apply 、call 则是立即执行 。