服务端与网络

1. http/https 协议

1.0 协议缺陷:

  • 无法复用链接,完成即断开,重新慢启动和 TCP 3次握手
  • head of line blocking: 线头阻塞,导致请求之间互相影响

1.1 改进:

  • 长连接(默认 keep-alive),复用
  • host 字段指定对应的虚拟站点

阅读全文

数组去重

今天总结一下数组去重的一些方法。记录一下。在真实的项目中碰到的数组去重,一般都是后台去处理,很少让前端处理这种问题。虽然日常项目用到的比较少,但我们还是需要了解一下,以防面试的时候可能回被问到。如果是被提问到,数组去重的方法有哪些?你能答出其中的几种?

一、利用 ES6 Set 去重

1
2
Array.from(new Set([1,2,3,3,4,4])) //[1,2,3,4]
[...new Set([1,2,3,3,4,4])] //[1,2,3,4]

set 是 ES6 新出来的一种一种定义不重复数组的数据类型
Array.from 是将类数组转化为数组
…是扩展运算符,将 set 里面的值转化为字符串

阅读全文

项目性能优化

1. 编码优化

编码优化,指的就是 在代码编写时的,通过一些 最佳实践,提升代码的执行性能。通常这并不会带来非常大的收益,但这属于 程序猿的自我修养,而且这也是面试中经常被问到的一个方面,考察自我管理与细节的处理。

数据读取:
通过作用域链 / 原型链 读取变量或方法时,需要更多的耗时,且越长越慢;
对象嵌套越深,读取值也越慢;
最佳实践:

  • 尽量在局部作用域中进行 变量缓存;
  • 避免嵌套过深的数据结构,数据扁平化 有利于数据的读取和维护;

阅读全文

跨域解决方案

通过jsonp跨域
通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。

原生实现:

1
2
3
4
5
6
7
8
9
10
11
var script = document.createElement('script');
script.type = 'text/javascript';

// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.daxihong.com:8080/login?user=admin&callback=jsonCallback';
document.head.appendChild(script);

// 回调执行函数
function jsonCallback(res) {
alert(JSON.stringify(res));
}

阅读全文

存储

我们经常需要对业务中的一些数据进行存储,通常可以分为 短暂性存储 和 持久性储存。

短暂性的时候,我们只需要将数据存在内存中,只在运行时可用

持久性存储,可以分为 浏览器端 与 服务器端

浏览器:

  • cookie: 通常用于存储用户身份,登录状态等
  • http 中自动携带, 体积上限为 4K, 可自行设置过期时间
  • localStorage / sessionStorage: 长久储存/窗口关闭删除, 体积限制为 4~5M
  • indexDB

服务器:

  • 分布式缓存 redis
  • 数据库

从输入 url 到展示的过程

DNS 解析
TCP 三次握手
发送请求,分析 url,设置请求报文(头,主体)
服务器返回请求的文件 (html)
浏览器渲染
1.HTML parser –> DOM Tree
标记化算法,进行元素状态的标记
dom 树构建
2.CSS parser –> Style Tree
解析 css 代码,生成样式树
3.attachment –> Render Tree
结合 dom树 与 style树,生成渲染树
4.layout: 布局
GPU painting: 像素绘制页面

安全

SQL 注入

这是一种比较简单的攻击方式。

如果后台人员使用用户输入的数据来组装SQL查询语句的时候不做防范, 遇到一些恶意的输入, 最后生成的SQL就会有问题。
比如地址栏输入的是:

1
articlrs/index.php?id=1

发送一个get请求, 调用的查询语句是:

1
sql = "SELECT * FROM articles WHERE id =", $id

阅读全文

模块化

模块化开发在现代开发中已是必不可少的一部分,它大大提高了项目的可维护、可拓展和可协作性。通常,我们 在浏览器中使用 ES6 的模块化支持,在 Node 中使用 commonjs 的模块化支持。

在有 Babel 的情况下,我们可以直接使用 ES6 的模块化

1
2
3
4
5
6
7
8
// file a.js
export function a() {}
export function b() {}
// file b.js
export default function () {}

import { a, b } from "./a.js";
import XXX from "./b.js";

阅读全文

继承

今天我们来说一下继承,在ES5中,我们可以使用如下方式解决继承的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Super() {}
Super.prototype.getNumber = function() {
return 1
}

function Sub() {}
let s = new Sub()
Sub.prototype = Object.create(Super.prototype, {
constructor: {
value: Sub,
enumerable: false,
writable: true,
configurable: true
}
})

阅读全文

防抖节流

今天我们来说一下防抖和节流,防抖与节流函数是一种最常用的 高频触发优化方式,能对性能有较大的帮助。

防抖

防抖 (debounce): 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。使用场景:
1.给按钮加函数防抖防止表单多次提交。
2.对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数。

我们先来看一个袖珍版的防抖理解一下防抖的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// func是用户传入需要防抖的函数
// wait是等待时间
const debounce = (func, wait = 50) => {
// 缓存一个定时器id
let timer = 0
// 这里返回的函数是每次用户实际调用的防抖函数
// 如果已经设定过定时器了就清空上一次的定时器
// 开始一个新的定时器,延迟执行用户传入的方法
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
// 不难看出如果用户调用该函数的间隔小于wait的情况下,上一次的时间还未到就被清除了,并不会执行函数

这是一个简单版的防抖,但是有缺陷,这个防抖只能在最后调用。一般的防抖会有immediate选项,表示是否立即调用。这两者的区别,举个栗子来说:

阅读全文