Review(一)

1.Promise中await的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
function fn(){
return new Promise((resolve,reject)=>{
resolve([1,2,3]);
})
}
async function getData(){
await fn();
console.log(1);
}
getData();
Promise.resolve().then(data=>{
console.log(2);
});

分析:在node中会编译成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function fn(){
return new Promise((resolve,reject)=>{
resolve([1,2,3]);
})
}
async function getData(){
/*
await fn();
console.log(1);
*/
// 上述代码node 中会编译成如下: 这里resolve(fn()),resolve里面返回的是promise,会等待这个promise成功完成(即这个promise里面的resolve()之后的then,line18执行完)之后,再执行最外层的then()line13
new Promise((resolve,reject)=>resolve(fn())).then(()=>{
console.log(1);
})
}
getData();
Promise.resolve().then(data=>{
console.log(2);
});
// 执行结果: 2 1

分析:在浏览器中会编译如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function fn(){
return new Promise((resolve,reject)=>{
resolve([1,2,3]);
})
}
async function getData(){
/*
await fn();
console.log(1);
*/
// 上述代码在浏览器中会编译成如下:
Promise.resolve(fn()).then(()=>{
console.log(1);
})
}
getData();
Promise.resolve().then(data=>{
console.log(2);
});
// 执行结果: 1 2

2.编码问题

  • ASCII -> ANSI(GB2312) -> GBK -> GB18030 -> Unicode -> UTF-8
  • base64编码 缺点比以前大
  • 编码问题
    1
    2
    3
    4
    5
    var iconv = require('iconv-lite'); // node中的编码转化
    function readGBKText(pathname) {
    var bin = fs.readFileSync(pathname); // 这里需要读出来二进制
    return iconv.decode(bin, 'gbk');
    }

3.Buffer方法

  • 分配方法 alloc 、from
  • slice toString concat isBuffer length(split)

4.核心模块 fs 、event、 path、stream

fs:

  • readFile writeFile
  • (open read write)
  • mkdir access stat unlink
  • createReadStream createWriteStream (pipe用法)

event:

  • on emit off once (newListener)

path:

  • join resolve extname dirname __dirname __filename

    流的类型:

  • 1)可读(on(‘data’),on(‘end’)) req

  • 2)可写 write.end res

  • 3)双工

  • 4)转化流 lib createGzip

5.HTTP (tcp用法)

1).一个页面从输入url到页面加载完成显示,这个过程做了什么?

  • 1). 浏览器通过DNS将url地址解析为ip (如果有缓存直接返回缓存,否则递归解析)
  • 2). 通过DNS解析得到了目标服务器的IP地址后,与服务器建立TCP连接。
    • ip协议: 选择传输路线,负责找到
    • tcp协议: 三次握手,分片,可靠传输,重新发送的机制 (tcp)
  • 3).浏览器通过http协议发送请求 (增加http的报文信息)
  • 4).服务器接受请求后,查库,读文件,拼接好返回的http响应
  • 5).浏览器收到html,开始渲染 (浏览器的渲染原理)
  • 6).解析html为dom,解析css为css-tree,最终生成render-tree 阻塞渲染
  • 7).遍历渲染树开始布局,计算每个节点的位置大小信息
  • 8).将渲染树每个节点绘制到屏幕
  • 9).加载js文件,运行js脚本
  • 10).reflow (样式)与repaint(位置)

OSI协议分层:

  • 应用层 HTTP,FTP,DNS (与其他计算机进行通讯的一个应用服务,向用户提供应用服务时的通信活动)
  • 传输层 TCP(可靠) UDP 数据传输 (HTTP -> TCP DNS->UDP)
  • 网络层 IP 选择传输路线 (通过ip地址和mac地址)(使用ARP协议凭借mac地址进行通信)
  • 链路层 网络连接的硬件部分

2).Http与Https的区别:

缺陷:
- 1).Http本身不具备加密的功能,HTTP 报文使用明文方式发送
- 2).无法确认你发送到的服务器就是真正的目标服务器
- 3).无法阻止海量请求下的 DoS 攻击
- 4).内容被篡改

  • HTTPS 是 HTTP 建立在 SSL/TLS 安全协议上的。 (信息加密,完整校验,身份验证)

3).URI和URL的区别

  • URI(Uniform Resource Identifier)是统一资源标识符,在某个规则下能把这个资源独一无二标示出来
  • URL(Uniform Resource Locator) 统一资源定位符,表示资源的地点

4).HTTP1.1版本特性

  • 长链接:建立链接后可以发送多次请求
  • 管线化:不用等待可以直接发送下一个请求
  • 断点续传:206 bytes

5).常见的http状态码

  • 200、204、206(Partial Content 响应了部分内容,断点续传)、301、302、304、400(参数错误,比如发个ajax参数不对)、401、403、404、500(服务器宕了)、503(负载匀衡挂了)

6).常用的http方法有哪些

  • GET 获取资源
  • POST 向服务器端发送数据,传输实体主体
  • PUT 传输文件
  • HEAD 获取报文首部
  • DELETE 删除文件
  • OPTIONS 询问支持的方法

7).Jsonp的原理 (不符合规范的)

新建 server.js、http.html

1
2
3
4
5
6
7
8
9
// server.js
const http = require('http');

http.createServer((req,res)=>{
// script标签是支持跨域的
if(req.url === '/jsonp'){
res.end(`fn({name: 'jf'})`); // 返回一个函数执行,并把参数带过去
}
}).listen(3000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--http.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>

<script>
function fn(data){
console.log("打印接收到的数据:",data); // {name: "jf"}
}
</script>
<script src="http://localhost:3000/jsonp"></script>
</body>
</html>

8).页面的性能优化

img

如何查看这些属性: 浏览器 => console.log => 打印 performance

  • 缓存
    强制缓存 & 对比缓存

    from memory cache 和 from disk cache(哪里看?打开百度 => network => size)
    查找优先级:

    • Service Worker (PWA) cacheApi 离线缓存

    • Memory Cache 网页关闭则失效 (几乎所有的请求资源)

    • DiskCache

    • 网络请求

      对于大文件来说,大概率是不存储在内存中的,当前系统内存使用率高的话,文件优先存储进硬盘

  • gzip压缩 重复率越高 压缩越高

  • 本地存储:localStorage,sessionStorage,session,cookie,indexDB,cacheApi

  • CDN: 内容分发网络,实现负载均衡,并且就近返回内容

  • defer & async / preload & prefetch

    • defer 和 async 在网络读取的过程中都是异步解析
    • defer是有顺序依赖的(defer按顺序执行),async只要脚本加载完后就会执行( async 谁先加载完谁先执行 )
    • preload 可以对当前页面所需的脚本、样式等资源进行预加载 vue 路由懒加载
    • prefetch 加载的资源一般不是用于当前页面的,是未来很可能用到的这样一些资源

HTTP相关Header内容

  • 缓存Header
    • 强:Cache-Control && Expires
      • private 客户端可以缓存
      • public 客户端和代理服务器都可以缓存
      • max-age=60 缓存内容将在60秒后失效
      • no-cache 需要使用对比缓存验证数据,强制向源服务器再次验证,验证通过则走缓存 (没有强制缓存)
      • no-store 所有内容都不会缓存,强制缓存和对比缓存都不会触发 (不缓存)
    • 对比:Last-Modified & If-Modified-Since / ETag & If-None-Match
  • 跨域:Access-Control
  • 压缩:Content-Encoding : gzip
  • 范围请求:range
  • 防盗链:referer (防止盗用链接)
  • 用户内核:user-agent
  • 单主机多域名:host 代理
  • 多语言:accept-language
  • 文件上传:Content-Type:multipart/form-data
  • 文件下载:Content-Description

6.KOA

compose的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let app = {
arr:[],
use(fn){
this.arr.push(fn);
},
compose(){
const dispatch = (index)=>{
if(index === this.arr.length) return Promise.resolve();
let middle = this.arr[index];
return Promise.resolve(middle(()=>dispatch(index+1)));
}
return dispatch(0); // 这里要返回 且返回的是个promise 因为line15后面是.then()
},
run(){
this.compose().then(()=>{
console.log('ok');
})
}
}
app.use((next)=>{
console.log(1);
next();
})
app.use((next)=>{
console.log(2);
next();
})
app.use((next)=>{
console.log(3);
next();
})

app.run(); // 调用
  • reduce
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
let app = {
arr:[],
use(fn){
this.arr.push(fn);
},
compose(){
// const dispatch = (index)=>{
// if(index === this.arr.length) return Promise.resolve();
// let middle = this.arr[index];
// return Promise.resolve(middle(()=>dispatch(index+1)));
// }
// return dispatch(0);

// this.arr.reduce((a,b)=>()) // this.compose() 返回的是个函数
// this.arr.reduce((a,b)=>()=>Promise.resolve()) // .then 后面接的是.then 返回一个promise
// this.arr.reduce((a,b)=>()=>Promise.resolve(a(()=>b()))) // Promise.resolve(a(()=>b())) 这里的内容可以和line10对比
return this.arr.reduce((a,b)=>(...args)=>{ // 这个 ...args就是外面传的这个空函数
return Promise.resolve(a(()=>b(...args)));
})(()=>{}) //这里传一个空函数 line 40最后一个next调的就是一个空函数

// 格式优化
// return this.arr.reduce((a,b)=>(...args)=>Promise.resolve(a(()=>b(...args))))(()=>{})
},
run(){
this.compose().then(()=>{
console.log('ok');
})
}
}
app.use((next)=>{
console.log(1);
next();
})
app.use((next)=>{
console.log(2);
next(); // 如果将这里注释 打印 1 2 ok
})
app.use((next)=>{
console.log(3);
next();
})

app.run(); // 调用

// Run Code 1 2 3 ok
1
2
3
4
5
let fn = this.arr.reduce((a, b, index) => (...args) =>
Promise.resolve(a(() => b(...args)))
)(() => {}).then(()=>{
console.log('ok')
})
  • async + await
1
2
3
4
5
 const dispatch = async (index) => {
if(index === this.arr.length) return;
return this.arr[index](()=>dispatch(index+1));
};
return dispatch(0);

async 后面返回的就是promise,不需要再 Promise.resolve()

反柯里化

反柯里化就是 让某个函数扩大应用的范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Object.prototype.toString.call();
// 这个方法只能在Object原型上用
// 柯里化就是让这个(toString)函数更具体一些,toString具体到Object.prototype上

// 反柯里化就是让这个函数的范围变大一些
Function.prototype.uncurrying = function(){
// 返回的是函数
return (str) => {
return this.call(str);
}
}
let toString = Object.prototype.toString.uncurrying();
console.log(toString('hello')); // 返回的是 [object String]
console.log(Object.prototype.toString('hello')); // [object Object]