-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
375 lines (180 loc) · 203 KB
/
search.xml
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>网络知识学习1</title>
<link href="/posts/ce9149eb.html"/>
<url>/posts/ce9149eb.html</url>
<content type="html"><![CDATA[<h1 id="计算机网络"><a href="#计算机网络" class="headerlink" title="计算机网络"></a>计算机网络</h1><h1 id="HTTP-协议"><a href="#HTTP-协议" class="headerlink" title="HTTP 协议"></a>HTTP 协议</h1><h2 id="GET-和-POST-的区别"><a href="#GET-和-POST-的区别" class="headerlink" title="GET 和 POST 的区别"></a>GET 和 POST 的区别</h2><table><thead><tr><th align="left"></th><th align="center">GET</th><th align="right">POST</th></tr></thead><tbody><tr><td align="left">后退/刷新</td><td align="center">无害</td><td align="right">不可收藏为书签</td></tr><tr><td align="left">书签</td><td align="center">可收藏为书签</td><td align="right">不可收藏为书签</td></tr><tr><td align="left">缓存</td><td align="center">能被缓存</td><td align="right">不能被缓存</td></tr><tr><td align="left">编码类型</td><td align="center">application/x-www-form-urlencoded</td><td align="right">application/x-www-form-urlencoded 或 multipart/from-data。为二进制数据使用多重编码</td></tr><tr><td align="left">历史</td><td align="center">参数保留在浏览器历史中</td><td align="right">不会被保留</td></tr><tr><td align="left">对数据长度的限制</td><td align="center">根据浏览器的不同会有不同的长度限制(基本是 2048)</td><td align="right">无限制</td></tr><tr><td align="left">对数据类型的限制</td><td align="center">只允许 ASCII 字符</td><td align="right">没有限制</td></tr><tr><td align="left">可见性</td><td align="center">URL 对所有人可见</td><td align="right">不在 URL</td></tr></tbody></table><h3 id="缓存问题:"><a href="#缓存问题:" class="headerlink" title="缓存问题:"></a>缓存问题:</h3><pre><code>首先要了解什么是缓存。HTTP 缓存的基本目的就是使应用执行的更快,更易扩展,但是 HTTP 缓存通常只适用于 idempotent request(可以理解为查询请求,也就是不更新服务端数据的请求),这也就导致了在 HTTP 的世界里,一般都是对 Get 请求做缓存,Post 请求很少有缓存。get 多用来直接获取数据,不修改数据,主要目的就是 DB 的 search 语句的感觉。用缓存(有个代理服务器的概念)的目的就是查 db 的速度变快。post 则是发送数据到服务器端去存储。类似 db 里的 update delete 和 insert 语句的感觉。更新 db 的意思。数据必须放在数据库,所以一般都得去访问服务器端。</code></pre><h3 id="安全问题:"><a href="#安全问题:" class="headerlink" title="安全问题:"></a>安全问题:</h3><pre><code>POST 比 GET 安全这种说法是因为,因为数据在地址栏上不可见然而从传输的角度来说,他们都是不安全的,因为 HTTP 在网络上是明文传输,只要在网络节点上抓包,就能完整地获取数据报文。要想安全传输,就只有加密,也就是 HTTPS</code></pre><h2 id="常见的-HTTP-请求头和响应头"><a href="#常见的-HTTP-请求头和响应头" class="headerlink" title="常见的 HTTP 请求头和响应头"></a>常见的 HTTP 请求头和响应头</h2><pre><code>一、 请求头: 1.Accept 告诉服务器,客户端支持的数据类型 2.Accept-Encoding 告诉服务器,客户机支持的数据压缩格式。 3.Accept-Language 告诉服务器,客户机的语言环境。 4.Connection 客户机通过这个头告诉服务器,请求完后是关闭还是保持链接。 5.Content-Length 表示请求消息正文的长度。 6.Content-Type 客户机通过这个头告诉服务器,客户端向服务器发送的数据类型。 7.Cookie 客户机通过这个头告诉服务器,可以向服务器带数据。 8.Host 客户机通过这个头告诉服务器,想访问的主机名。 9.Origin 用来说明请求从哪里发起的,包括且仅仅包括协议和域名。 这个参数一般只存在于CORS跨域请求中,可以看到response有对应的header:Access-Control-Allow-Origin。 10.Referer 客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的。(一般用于防盗链) 11.User-Agent 客户机通过这个头告诉服务器,客户机的软件环境。 12.Accept-Charset: 告诉服务器,客户端采用的编码。 13.Date: 客户机通过这个头告诉服务器,客户机当前请求时间。 14.If-Modified-Since 客户机通过这个头告诉服务器,资源的缓存时间。二.响应头 1.Connection 服务器通过这个头,响应完是保持链接还是关闭链接。 2.Content-Encoding 服务器通过这个头,告诉浏览器数据采用的压缩格式。 3.Content-Type 服务器通过这个头,回送数据的类型 常见的 Content-Type 属性值有以下四种: (1)application/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码。 (2)multipart/form-data:该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。 (3)application/json:服务器消息主体是序列化后的 JSON 字符串。 (4)text/xml:该种方式主要用来提交 XML 格式的数据。 4.Date 告诉客户机,返回响应的时间。 5.Server 服务器通过这个头,告诉浏览器服务器的类型 6.Transfer-Encoding HTTP协议头字段Transfer_Encoding,分块传输编码,一般出现在http的响应头中。该头字段存在与HTTP协议的1.1版本中,提供一种数据传输机制。 通常http协议在传输数据时是整体一起发送的,数据体的长度由Content-Length字段指定,方便判断消息结束。 服务器通过这个头,告诉浏览器数据的传送格式。 7.vary Vary 字段用于列出一个响应字段列表,告诉缓存服务器遇到同一个 URL 对应着不同版本文档的情况时,如何缓存和筛选合适的版本。 8.Location 这个头配合302状态码使用,告诉用户端找谁。 9.Content-Length 服务器通过这个头,告诉浏览器回送数据的长度 10.Content-Language 服务器通过这个头,告诉服务器的语言环境 11.Last-Modified 服务器通过这个头,告诉浏览器当前资源的缓存时间 12.Refresh 服务器通过这个头,告诉浏览器隔多长时间刷新一次 13.Content-Disposition 服务器通过这个头,告诉浏览器以下载的方式打开数据。 14.ETag:与缓存相关的头。 (1)Expires 服务器通过这个头,告诉浏览器把回送的数据缓存多长时间。-1或0不缓存。 (2)Cache-Control和Pragma 服务器通过这个头,也可以控制浏览器不缓存数据</code></pre><h2 id="常见的-HTTP-请求方法:"><a href="#常见的-HTTP-请求方法:" class="headerlink" title="常见的 HTTP 请求方法:"></a>常见的 HTTP 请求方法:</h2><pre><code>1. GET: 向服务器获取数据;2. POST:将实体提交到指定的资源,通常会造成服务器资源的修改;3. PUT:上传文件,更新数据;4. DELETE:删除服务器上的对象;5. HEAD:获取报文首部,与GET相比,不返回报文主体部分; 比如,想要检查一个文件是否存在,只要发个 HEAD 请求就可以了,没有必要用 GET 把整个文件都取下来。再比如,要检查文件是否有最新版本,同样也应该用 HEAD,服务器会在响应头里把文件的修改时间传回来。6. OPTIONS:询问支持的请求方法,用来跨域请求; 方法要求服务器列出可对资源实行的操作方法,在响应头的 Allow 字段里返回。它的功能很有限,用处也不大,有的服务器(例如 Nginx)干脆就没有实现对它的支持。7. CONNECT:要求在与代理服务器通信时建立隧道,使用隧道进行TCP通信; 是一个比较特殊的方法,要求服务器为客户端和另一台远程服务器建立一条特殊的连接隧道,这时 Web 服务器在中间充当了代理的角色。8. TRACE: 回显服务器收到的请求,主要⽤于测试或诊断。 法多用于对 HTTP 链路的测试或诊断,可以显示出请求 - 响应的传输路径。它的本意是好的,但存在漏洞,会泄漏网站的信息,所以 Web 服务器通常也是禁止使用。</code></pre><h2 id="HTTP1-0-和-HTTP1-1"><a href="#HTTP1-0-和-HTTP1-1" class="headerlink" title="HTTP1.0 和 HTTP1.1"></a>HTTP1.0 和 HTTP1.1</h2><pre><code>1. 连接方面,http1.0 默认使用非持久连接,而 http1.1 默认使用持久连接。http1.1 通过使用持久连接来使多个 http 请求复用同一个 TCP 连接,以此来避免使用非持久连接时每次需要建立连接的时延。2. 状态响应码 : HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,100 (Continue)——在请求大资源前的预热请求,206 (Partial Content)——范围请求的标识码,409 (Conflict)——请求与当前资源的规定冲突,410 (Gone)——资源已被永久转移,而且没有任何已知的转发地址。3. Host 头处理 : HTTP/1.1 在请求头中加入了Host字段。4. 缓存方面,在 http1.0 中主要使用 header 里的 If-Modified-Since、Expires 来做为缓存判断的标准,http1.1 则引入了更多的缓存控制策略,例如 Etag、If-Unmodified-Since、If-Match、If-None-Match 等更多可供选择的缓存头来控制缓存策略。5. 资源请求方面,在 http1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,http1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。</code></pre><h2 id="什么是-HTTP1-1-断点续传"><a href="#什么是-HTTP1-1-断点续传" class="headerlink" title="什么是 HTTP1.1 断点续传"></a>什么是 HTTP1.1 断点续传</h2><h3 id="断点续传原理"><a href="#断点续传原理" class="headerlink" title="断点续传原理"></a>断点续传原理</h3><pre><code>文件在网络传输过程中时常会面对网络中断的情况,对于比较大的文件(花了30分钟上传了1G,还剩下2G没有完成)突然网断了,若重头开始上传的话前面花费30分钟时间上次的1G就完全浪费了(浪费时间、浪费流量),所以需要有一种机制可以从中断地方继续开始上传,这就是"断点续传"的概念。</code></pre><h3 id="断点存储"><a href="#断点存储" class="headerlink" title="断点存储"></a>断点存储</h3><pre><code>一般文件远程传输时不是直接存储为原文件格式,会存储为一个临时的格式,比如".temp",当文件传输完成后再修改为原文件格式名,比较常用的做法是之间在原文件名的后缀后面添加“.temp”后缀,如:“001.txt.temp”对于只是续传来说临时文件的大小就可以认为是当前的断点,因为是往后追加方式存储,也有很多的下载上传工具(QQ旋风,迅雷,FTP客户端等)是支持多线程并发传输的,这个时候需要分配并记录多个断点。比如:一个1024byte大小文件在远程接收时,以200byte为一个缓存块进行传输文件,也就是分隔成“0-200,201-401,402-602,603-803,804-1004,1005-1024”并行传输,传输效率提升非常可观。</code></pre><h3 id="文件续传读取"><a href="#文件续传读取" class="headerlink" title="文件续传读取"></a>文件续传读取</h3><pre><code>比如已经存储到508byte大小,那么需要从509byte开始上传,对于发送客户端需要从指定位置开始读取指定长度的文件字节码,发送给接收端。可以通过具体SDK包方法移动到文件某个字节位置开始读取指定大小,目前的开发语言库基本都支持此类的开发包。</code></pre><h3 id="文件续传存储"><a href="#文件续传存储" class="headerlink" title="文件续传存储"></a>文件续传存储</h3><pre><code>文件在网络中传输是通过字节码方式作为一个文件流。接收端收到的文件字节码流需要带有标志信息,如“337byte-797byte”,这样就可以把该字节流存储到临时文件中该指定位置,多次续传最终拼接成一个完整的文件。</code></pre><h3 id="文件校验-判断是否变化"><a href="#文件校验-判断是否变化" class="headerlink" title="文件校验-判断是否变化"></a>文件校验-判断是否变化</h3><pre><code>在实际的上传下载操作中,存在文件发送过程中被变更的场景,所以在续传时需要明确知道文件是否变动,否则存储就会出现数据错误。没有变动继续续传,有变动重新开始传输。本质是在文件传输端生成一个标志,发送给接收的端每次去比对是否一直一样。</code></pre><h2 id="HTTP1-1-和-HTTP2-0-的区别"><a href="#HTTP1-1-和-HTTP2-0-的区别" class="headerlink" title="HTTP1.1 和 HTTP2.0 的区别"></a>HTTP1.1 和 HTTP2.0 的区别</h2><pre><code>1. 二进制协议:HTTP/2 是一个二进制协议。在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础。2. 多路复用:HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了"队头堵塞"的问题。3. 数据流:HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。4. 头信息压缩:HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。5. 服务器推送:HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。这里需要注意的是 http2 下服务器主动推送的是静态资源,</code></pre><h3 id="HTTP2-0-头部压缩算法"><a href="#HTTP2-0-头部压缩算法" class="headerlink" title="HTTP2.0 头部压缩算法"></a>HTTP2.0 头部压缩算法</h3><pre><code>HTTP2的头部压缩是HPACK算法。在客户端和服务器两端建立“字典”,用索引号表示重复的字符串,采用哈夫曼编码来压缩整数和字符串,可以达到50%~90%的高压缩率。具体来说: 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送; 首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新; 每个新的首部键值对要么被追加到当前表的末尾,要么替换表中之前的值。</code></pre><h2 id="对-keep-alive-的理解"><a href="#对-keep-alive-的理解" class="headerlink" title="对 keep-alive 的理解"></a>对 keep-alive 的理解</h2><pre><code>HTTP1.0 中默认是在每次请求/应答,客户端和服务器都要新建一个连接,完成之后立即断开连接,这就是短连接。当使用Keep-Alive模式时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接,这就是长连接。其使用方法如下:HTTP1.0版本是默认没有Keep-alive的(也就是默认会发送keep-alive),所以要想连接得到保持,必须手动配置发送Connection: keep-alive字段。若想断开keep-alive连接,需发送Connection:close字段;HTTP1.1规定了默认保持长连接,数据传输完成了保持TCP连接不断开,等待在同域名下继续用这个通道传输数据。如果需要关闭,需要客户端发送Connection:close首部字段。Keep-Alive的建立过程: 客户端向服务器在发送请求报文同时在首部添加发送Connection字段 服务器收到请求并处理 Connection字段 服务器回送Connection:Keep-Alive字段给客户端 客户端接收到Connection字段 Keep-Alive连接建立成功、服务端自动断开过程(也就是没有keep-alive): 客户端向服务器只是发送内容报文(不包含Connection字段) 服务器收到请求并处理 服务器返回客户端请求的资源并关闭连接 客户端接收资源,发现没有Connection字段,断开连接客户端请求断开连接过程: 客户端向服务器发送Connection:close字段 服务器收到请求并处理connection字段 服务器回送响应资源并断开连接 客户端接收资源并断开连接开启Keep-Alive的优点: 较少的CPU和内存的使⽤(由于同时打开的连接的减少了); 允许请求和应答的HTTP管线化; 降低拥塞控制 (TCP连接减少了); 减少了后续请求的延迟(⽆需再进⾏握⼿); 报告错误⽆需关闭TCP连;开启Keep-Alive的缺点: 长时间的Tcp连接容易导致系统资源无效占用,浪费系统资源。</code></pre><h2 id="页面中有多张图片,HTTP-是怎样的加载表现"><a href="#页面中有多张图片,HTTP-是怎样的加载表现" class="headerlink" title="页面中有多张图片,HTTP 是怎样的加载表现"></a>页面中有多张图片,HTTP 是怎样的加载表现</h2><pre><code>在HTTP 1下,浏览器对一个域名下最大TCP连接数为6,所以会请求多次。可以用多域名部署解决。这样可以提高同时请求的数目,加快页面图片的获取速度。在HTTP 2下,可以一瞬间加载出来很多资源,因为,HTTP2支持多路复用,可以在一个TCP连接中发送多个HTTP请求。</code></pre><h2 id="HTTP-和-HTTPS-协议的主要区别如下:"><a href="#HTTP-和-HTTPS-协议的主要区别如下:" class="headerlink" title="HTTP 和 HTTPS 协议的主要区别如下:"></a>HTTP 和 HTTPS 协议的主要区别如下:</h2><pre><code>HTTPS协议需要CA证书,费用较高;而HTTP协议不需要;HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;HTTP协议连接很简单,是无状态的;HTTPS协议是有SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP更加安全。</code></pre><h2 id="HTTP-协议的优点和缺点"><a href="#HTTP-协议的优点和缺点" class="headerlink" title="HTTP 协议的优点和缺点"></a>HTTP 协议的优点和缺点</h2><pre><code>HTTP 是超文本传输协议,它定义了客户端和服务器之间交换报文的格式和方式,默认使用 80 端口。它使用 TCP 作为传输层协议,保证了数据传输的可靠性。HTTP协议具有以下优点:1. 支持客户端/服务器模式2. 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。由于 HTTP 协议简单,使得 HTTP 服务器的程序规模小,因而通信速度很快。3. 无连接:无连接就是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接,采用这种方式可以节省传输时间。4. 无状态:HTTP 协议是无状态协议,这里的状态是指通信过程的上下文信息。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能会导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就比较快。5. 灵活:HTTP 允许传输任意类型的数据对象。正在传输的类型由 Content-Type 加以标记。</code></pre><h2 id="HTTP3-0"><a href="#HTTP3-0" class="headerlink" title="HTTP3.0"></a>HTTP3.0</h2><h1 id="HTTPS"><a href="#HTTPS" class="headerlink" title="HTTPS"></a>HTTPS</h1><h2 id="什么是-HTTPS-协议?"><a href="#什么是-HTTPS-协议?" class="headerlink" title="什么是 HTTPS 协议?"></a>什么是 HTTPS 协议?</h2><pre><code>超文本传输安全协议(Hypertext Transfer Protocol Secure,简称:HTTPS)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,利用SSL/TLS来加密数据包。HTTPS的主要目的是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。HTTP协议采用明文传输信息,存在信息窃听、信息篡改和信息劫持的风险,而协议TLS/SSL具有身份验证、信息加密和完整性校验的功能,可以避免此类问题发生。安全层的主要职责就是对发起的HTTP请求的数据进行加密操作 和 对接收到的HTTP的内容进行解密操作。</code></pre><h2 id="TLS-SSL-的工作原理"><a href="#TLS-SSL-的工作原理" class="headerlink" title="TLS/SSL 的工作原理"></a>TLS/SSL 的工作原理</h2><pre><code>TLS/SSL全称安全传输层协议(Transport Layer Security), 是介于TCP和HTTP之间的一层安全协议,不影响原有的TCP协议和HTTP协议,所以使用HTTPS基本上不需要对HTTP页面进行太多的改造。TLS/SSL的功能实现主要依赖三类基本算法:散列函数hash、对称加密、非对称加密。这三类算法的作用如下: 基于散列函数验证信息的完整性 对称加密算法采用协商的秘钥对数据加密 非对称加密实现身份认证和秘钥协商</code></pre><h3 id="散列函数"><a href="#散列函数" class="headerlink" title="散列函数"></a>散列函数</h3><pre><code>常见的散列函数有MD5、SHA1、SHA256。该函数的特点是单向不可逆,对输入数据非常敏感,输出的长度固定,任何数据的修改都会改变散列函数的结果,可以用于防止信息篡改并验证数据的完整性。</code></pre><h3 id="对称加密"><a href="#对称加密" class="headerlink" title="对称加密"></a>对称加密</h3><pre><code>对称加密的方法是,双方使用同一个秘钥对数据进行加密和解密。但是对称加密的存在一个问题,就是如何保证秘钥传输的安全性,因为秘钥还是会通过网络传输的,一旦秘钥被其他人获取到,那么整个加密过程就毫无作用了。 这就要用到非对称加密的方法。常见的对称加密算法有AES-CBC、DES、3DES、AES-GCM等。相同的秘钥可以用于信息的加密和解密。掌握秘钥才能获取信息,防止信息窃听,其通讯方式是一对一。</code></pre><h3 id="非对称加密"><a href="#非对称加密" class="headerlink" title="非对称加密"></a>非对称加密</h3><pre><code>非对称加密的方法是,我们拥有两个秘钥,一个是公钥,一个是私钥。公钥是公开的,私钥是保密的。用私钥加密的数据,只有对应的公钥才能解密,用公钥加密的数据,只有对应的私钥才能解密。我们可以将公钥公布出去,任何想和我们通信的客户, 都可以使用我们提供的公钥对数据进行加密,这样我们就可以使用私钥进行解密,这样就能保证数据的安全了。但是非对称加密有一个缺点就是加密的过程很慢,因此如果每次通信都使用非对称加密的方式的话,反而会造成等待时间过长的问题。常见的非对称加密算法有RSA、ECC、DH等。秘钥成对出现,一般称为公钥(公开)和私钥(保密)。公钥加密的信息只有私钥可以解开,私钥加密的信息只能公钥解开,因此掌握公钥的不同客户端之间不能相互解密信息,只能和服务器进行加密通信,服务器可以实现一对多的的通信,客户端也可以用来验证掌握私钥的服务器的身份。</code></pre><h2 id="数字证书是什么?"><a href="#数字证书是什么?" class="headerlink" title="数字证书是什么?"></a>数字证书是什么?</h2><pre><code>现在的方法也不一定是安全的,因为没有办法确定得到的公钥就一定是安全的公钥。可能存在一个中间人,截取了对方发给我们的公钥,然后将他自己的公钥发送给我们,当我们使用他的公钥加密后发送的信息,就可以被他用自己的私钥解密。然后他伪装成我们以同样的方法向对方发送信息,这样我们的信息就被窃取了,然而自己还不知道。为了解决这样的问题,可以使用数字证书。首先使用一种 Hash 算法来对公钥和其他信息进行加密,生成一个信息摘要,然后让有公信力的认证中心(简称 CA )用它的私钥对消息摘要加密,形成签名。最后将原始的信息和签名合在一起,称为数字证书。当接收方收到数字证书的时候,先根据原始信息使用同样的 Hash 算法生成一个摘要,然后使用公证处的公钥来对数字证书中的摘要进行解密,最后将解密的摘要和生成的摘要进行对比,就能发现得到的信息是否被更改了。这个方法最要的是认证中心的可靠性,一般浏览器里会内置一些顶层的认证中心的证书,相当于我们自动信任了他们,只有这样才能保证数据的安全。</code></pre><h2 id="HTTPS-通信(握手)过程"><a href="#HTTPS-通信(握手)过程" class="headerlink" title="HTTPS 通信(握手)过程"></a>HTTPS 通信(握手)过程</h2><pre><code>客户端向服务器发起请求,请求中包含使用的协议版本号、生成的一个随机数、以及客户端支持的加密方法。服务器端接收到请求后,确认双方使用的加密方法、并给出服务器的证书、以及一个服务器生成的随机数。客户端确认服务器证书有效后,生成一个新的随机数,并使用数字证书中的公钥,加密这个随机数,然后发给服务器。并且还会提供一个前面所有内容的 hash 的值,用来供服务器检验。服务器使用自己的私钥,来解密客户端发送过来的随机数。并提供前面所有内容的 hash 值来供客户端检验。客户端和服务器端根据约定的加密方法使用前面的三个随机数,生成对话秘钥,以后的对话过程都使用这个秘钥来加密信息。</code></pre><h2 id="HTTPS-的优缺点"><a href="#HTTPS-的优缺点" class="headerlink" title="HTTPS 的优缺点"></a>HTTPS 的优缺点</h2><pre><code>HTTPS的优点如下: 使用HTTPS协议可以认证用户和服务器,确保数据发送到正确的客户端和服务器; 使用HTTPS协议可以进行加密传输、身份认证,通信更加安全,防止数据在传输过程中被窃取、修改,确保数据安全性; HTTPS是现行架构下最安全的解决方案,虽然不是绝对的安全,但是大幅增加了中间人攻击的成本;HTTPS的缺点如下: HTTPS需要做服务器和客户端双方的加密个解密处理,耗费更多服务器资源,过程复杂; HTTPS协议握手阶段比较费时,增加页面的加载时间; SSL证书是收费的,功能越强大的证书费用越高; HTTPS连接服务器端资源占用高很多,支持访客稍多的网站需要投入更大的成本; SSL证书需要绑定IP,不能再同一个IP上绑定多个域名。</code></pre><h2 id="HTTPS-是如何保证安全的?"><a href="#HTTPS-是如何保证安全的?" class="headerlink" title="HTTPS 是如何保证安全的?"></a>HTTPS 是如何保证安全的?</h2><pre><code>先理解两个概念: 对称加密:即通信的双⽅都使⽤同⼀个秘钥进⾏加解密,对称加密虽然很简单性能也好,但是⽆法解决⾸次把秘钥发给对⽅的问题,很容易被⿊客拦截秘钥。 ⾮对称加密: \1. 私钥 + 公钥= 密钥对 \2. 即⽤私钥加密的数据,只有对应的公钥才能解密,⽤公钥加密的数据,只有对应的私钥才能解密 \3. 因为通信双⽅的⼿⾥都有⼀套⾃⼰的密钥对,通信之前双⽅会先把⾃⼰的公钥都先发给对⽅ \4. 然后对⽅再拿着这个公钥来加密数据响应给对⽅,等到到了对⽅那⾥,对⽅再⽤⾃⼰的私钥进⾏解密 ⾮对称加密虽然安全性更⾼,但是带来的问题就是速度很慢,影响性能。解决⽅案: 结合两种加密⽅式,将对称加密的密钥使⽤⾮对称加密的公钥进⾏加密,然后发送出去,接收⽅使⽤私钥进⾏解密得到对称加密的密钥,然后双⽅可以使⽤对称加密来进⾏沟通。 此时⼜带来⼀个问题,中间⼈问题: 如果此时在客户端和服务器之间存在⼀个中间⼈,这个中间⼈只需要把原本双⽅通信互发的公钥,换成⾃⼰的公钥,这样中间⼈就可以轻松解密通信双⽅所发送的所有数据。 所以这个时候需要⼀个安全的第三⽅颁发证书(CA),证明身份的身份,防⽌被中间⼈攻击。 证书中包括:签发者、证书⽤途、使⽤者公钥、使⽤者私钥、使⽤者的HASH算法、证书到期时间等。 但是问题来了,如果中间⼈篡改了证书,那么身份证明是不是就⽆效了?这个证明就⽩买了,这个时候需要⼀个新的技术,数字签名。 数字签名就是⽤CA⾃带的HASH算法对证书的内容进⾏HASH得到⼀个摘要,再⽤CA的私钥加密,最终组成数字签名。当别⼈把他的证书发过来的时候,我再⽤同样的Hash算法,再次⽣成消息摘要,然后⽤CA的公钥对数字签名解密,得到CA创建的消息摘要,两者⼀⽐,就知道中间有没有被⼈篡改了。这个时候就能最⼤程度保证通信的安全了。</code></pre><h1 id="状态码"><a href="#状态码" class="headerlink" title="状态码"></a>状态码</h1><table><thead><tr><th align="left">类别</th><th align="center">原因</th><th align="right">描述</th></tr></thead><tbody><tr><td align="left">1xx</td><td align="center">Informational(信息性状态码)</td><td align="right">接受的请求正在处理</td></tr><tr><td align="left">2xx</td><td align="center">Success(成功状态码)</td><td align="right">请求正常处理完毕</td></tr><tr><td align="left">3xx</td><td align="center">Redirection(重定向状态码)</td><td align="right">需要进行附加操作一完成请求</td></tr><tr><td align="left">4xx</td><td align="center">Client Error (客户端错误状态码)</td><td align="right">服务器无法处理请求</td></tr><tr><td align="left">5xx</td><td align="center">Server Error(服务器错误状态)</td><td align="right">服务器处理请求出错</td></tr></tbody></table><h2 id="2XX-成功状态码"><a href="#2XX-成功状态码" class="headerlink" title="2XX 成功状态码"></a>2XX 成功状态码</h2><pre><code>1. 200 OK表示客户端发来的请求被服务器端正常处理了。2. 204 该状态码表示客户端发送的请求已经在服务器端正常处理了,但是没有返回的内容,响应报文中不包含实体的主体部分。一般在只需要从客户端往服务器端发送信息,而服务器端不需要往客户端发送内容时使用。3. 206 该状态码表示客户端进行了范围请求,而服务器端执行了这部分的 GET 请求。响应报文中包含由 Content-Range 指定范围的实体内容。</code></pre><h2 id="3XX-重定向状态码"><a href="#3XX-重定向状态码" class="headerlink" title="3XX 重定向状态码"></a>3XX 重定向状态码</h2><pre><code>1. 301 永久重定向2. 302 临时重定向3. 304 浏览器缓存相关 状态码304并不是一种错误,而是告诉客户端有缓存,直接使用缓存中的数据。返回页面的只有头部信息,是没有内容部分的,这样在一定程度上提高了网页的性能。 (底下会对缓存细节讲述)4.307 临时重定向,和302含义类似,但是期望客户端保持请求方法不变向新的地址发出请求 和302的区别是302明确表示客户端应当采⽤get⽅法获取资源,他会把POST请求变为GET请求进⾏重定向。 307会遵照浏览器标准,不会从post变为get。</code></pre><h2 id="4XX"><a href="#4XX" class="headerlink" title="4XX"></a>4XX</h2><pre><code>1.400 该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码2.401 请求要求用户的身份认证3.403 代表客户端错误,指的是服务器端有能力处理该请求,但是拒绝授权访问4.404 该状态码表明服务器上无法找到请求的资源5.405 表示请求方法不对</code></pre><h2 id="5XX"><a href="#5XX" class="headerlink" title="5XX"></a>5XX</h2><pre><code>1.500 表示服务器端在执行请求时发生了错误2.501 表示服务器不支持当前请求所需要的某个功能3.503 表明服务器暂时处于超负载或正在停机维护,无法处理请求</code></pre><h1 id="网络模型"><a href="#网络模型" class="headerlink" title="网络模型"></a>网络模型</h1><h2 id="OSI-七层模型"><a href="#OSI-七层模型" class="headerlink" title="OSI 七层模型"></a>OSI 七层模型</h2><table><thead><tr><th align="center">OSI 参考模型</th><th align="right">各层的解释</th></tr></thead><tbody><tr><td align="center">应用层</td><td align="right">为应用程序提供服务</td></tr><tr><td align="center">表示层</td><td align="right">数据格式转化、数据加密</td></tr><tr><td align="center">会话层</td><td align="right">建立、管理和维护会话</td></tr><tr><td align="center">传输层</td><td align="right">建立、管理和维护端到端的建立</td></tr><tr><td align="center">网络层</td><td align="right">IP 选址及路由选择</td></tr><tr><td align="center">数据链路层</td><td align="right">提供介质访问和链路管理</td></tr><tr><td align="center">物理层</td><td align="right">物理层</td></tr></tbody></table><h3 id="应用层"><a href="#应用层" class="headerlink" title="应用层"></a>应用层</h3><pre><code>OSI参考模型中最靠近用户的一层,是为计算机用户提供应用接口,也为用户直接提供各种网络服务。我们常见应用层的网络服务协议有:HTTP,HTTPS,FTP,POP3、SMTP等。1. 在客户端与服务器中经常会有数据的请求,这个时候就是会用到http(hyper text transfer protocol)(超文本传输协议)或者https.在后端设计数据接口时,我们常常使用到这个协议。2. FTP是文件传输协议,在开发过程中,个人并没有涉及到,但是我想,在一些资源网站,比如百度网盘``迅雷应该是基于此协议的。3. SMTP是simple mail transfer protocol(简单邮件传输协议)。在一个项目中,在用户邮箱验证码登录的功能时,使用到了这个协议。</code></pre><h3 id="表示层"><a href="#表示层" class="headerlink" title="表示层"></a>表示层</h3><pre><code>表示层提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。如果必要,该层可提供一种标准表示形式,用于将计算机内部的多种数据格式转换成通信中采用的标准表示形式。数据压缩和加密也是表示层可提供的转换功能之一。在项目开发中,为了方便数据传输,可以使用base64对数据进行编解码。如果按功能来划分,base64应该是工作在表示层。</code></pre><h3 id="(3)会话层"><a href="#(3)会话层" class="headerlink" title="(3)会话层"></a>(3)会话层</h3><pre><code>会话层就是负责建立、管理和终止表示层实体之间的通信会话。该层的通信由不同设备中的应用程序之间的服务请求和响应组成。</code></pre><h3 id="传输层"><a href="#传输层" class="headerlink" title="传输层"></a>传输层</h3><pre><code>传输层建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,使高层用户看到的只是在两个传输实体间的一条主机到主机的、可由用户控制和设定的、可靠的数据通路。我们通常说的,TCP UDP就是在这一层。端口号既是这里的“端”。</code></pre><h3 id="网络层"><a href="#网络层" class="headerlink" title="网络层"></a>网络层</h3><pre><code>本层通过IP寻址来建立两个节点之间的连接,为源端的运输层送来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。就是通常说的IP层。这一层就是我们经常说的IP协议层。IP协议是Internet的基础。我们可以这样理解,网络层规定了数据包的传输路线,而传输层则规定了数据包的传输方式。</code></pre><h3 id="数据链路层"><a href="#数据链路层" class="headerlink" title="数据链路层"></a>数据链路层</h3><pre><code>将比特组合成字节,再将字节组合成帧,使用链路层地址 (以太网使用MAC地址)来访问介质,并进行差错检测。网络层与数据链路层的对比,通过上面的描述,我们或许可以这样理解,网络层是规划了数据包的传输路线,而数据链路层就是传输路线。不过,在数据链路层上还增加了差错控制的功能。</code></pre><h3 id="物理层"><a href="#物理层" class="headerlink" title="物理层"></a>物理层</h3><pre><code>实际最终信号的传输是通过物理层实现的。通过物理介质传输比特流。规定了电平、速度和电缆针脚。常用设备有(各种物理设备)集线器、中继器、调制解调器、网线、双绞线、同轴电缆。这些都是物理层的传输介质。</code></pre><h1 id="TCP-和-UDP"><a href="#TCP-和-UDP" class="headerlink" title="TCP 和 UDP"></a>TCP 和 UDP</h1><p>TCP 和 UDP 都是传输层协议,他们都属于 TCP/IP 协议族。</p><h2 id="UDP"><a href="#UDP" class="headerlink" title="UDP"></a>UDP</h2><pre><code>UDP的全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。</code></pre><h3 id="面向无连接:"><a href="#面向无连接:" class="headerlink" title="面向无连接:"></a>面向无连接:</h3><pre><code>首先 UDP 是不需要和 TCP一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。具体来说就是:在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作</code></pre><h3 id="有单播,多播,广播的功能"><a href="#有单播,多播,广播的功能" class="headerlink" title="有单播,多播,广播的功能"></a>有单播,多播,广播的功能</h3><pre><code>UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。</code></pre><h3 id="面向报文"><a href="#面向报文" class="headerlink" title="面向报文"></a>面向报文</h3><pre><code>发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文</code></pre><h3 id="不可靠性"><a href="#不可靠性" class="headerlink" title="不可靠性"></a>不可靠性</h3><pre><code>首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。</code></pre><h3 id="头部开销小,传输数据报文时是很高效的。"><a href="#头部开销小,传输数据报文时是很高效的。" class="headerlink" title="头部开销小,传输数据报文时是很高效的。"></a>头部开销小,传输数据报文时是很高效的。</h3><pre><code>UDP 头部包含了以下几个数据: 两个十六位的端口号,分别为源端口(可选字段)和目标端口 整个数据报文的长度 整个数据报文的检验和(IPv4 可选字段),该字段用于发现头部信息和数据中的错误 因此 UDP 的头部开销小,只有8字节,相比 TCP 的至少20字节要少得多,在传输数据报文时是很高效的。</code></pre><h2 id="TCP"><a href="#TCP" class="headerlink" title="TCP"></a>TCP</h2><p>TCP 的全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP 是面向连接的、可靠的流协议(流就是指不间断的数据结构)。</p><h3 id="面向连接"><a href="#面向连接" class="headerlink" title="面向连接"></a>面向连接</h3><pre><code>面向连接,是指发送数据之前必须在两端建立连接。建立连接的方法是“三次握手”,这样能建立可靠的连接。建立连接,是为数据的可靠传输打下了基础。</code></pre><h3 id="仅支持单播传输"><a href="#仅支持单播传输" class="headerlink" title="仅支持单播传输"></a>仅支持单播传输</h3><pre><code>每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。</code></pre><h3 id="面向字节流"><a href="#面向字节流" class="headerlink" title="面向字节流"></a>面向字节流</h3><pre><code>TCP 不像 UDP 一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。</code></pre><h3 id="可靠性"><a href="#可靠性" class="headerlink" title="可靠性"></a>可靠性</h3><pre><code>对于可靠传输,判断丢包、误码靠的是TCP的段编号以及确认号。TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。</code></pre><h3 id="提供拥塞控制"><a href="#提供拥塞控制" class="headerlink" title="提供拥塞控制"></a>提供拥塞控制</h3><pre><code>当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞。TCP的判断网络是否发生拥塞有两种方法: 1、是否发生超时 如果过了超时重传时间发送方仍未收到确认报文,那么TCP就会认为当前网络已经发生拥塞。采用慢开始算法进行处理。 2、收到连续3个重复的ACK报文 如果发送方收到了连续3个重复的ACK报文,那么TCP也会认为当前网络发生了拥塞。采用快恢复算法进行处理。</code></pre><h3 id="提供全双工通信"><a href="#提供全双工通信" class="headerlink" title="提供全双工通信"></a>提供全双工通信</h3><pre><code>TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都设有缓存,用来临时存放双向通信的数据。当然,TCP可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于MSS)</code></pre><h2 id="TCP-和-UDP-的使用场景"><a href="#TCP-和-UDP-的使用场景" class="headerlink" title="TCP 和 UDP 的使用场景"></a>TCP 和 UDP 的使用场景</h2><pre><code>TCP应用场景: 效率要求相对低,但对准确性要求相对高的场景。因为传输中需要对数据确认、重发、排序等操作,相比之下效率没有UDP高。例如:文件传输(准确高要求高、但是速度可以相对慢)、接受邮件、远程登录。UDP应用场景: 效率要求相对高,对准确性要求相对低的场景。例如:QQ聊天、在线视频、网络语音电话(即时通讯,速度要求高,但是出现偶尔断续不是太大问题,并且此处完全不可以使用重发机制)、广播通信(广播、多播)。</code></pre><h2 id="UDP-协议为什么不可靠"><a href="#UDP-协议为什么不可靠" class="headerlink" title="UDP 协议为什么不可靠"></a>UDP 协议为什么不可靠</h2><pre><code>UDP在传输数据之前不需要先建立连接,远地主机的运输层在接收到UDP报文后,不需要确认,提供不可靠交付。总结就以下四点: 不保证消息交付:不确认,不重传,无超时 不保证交付顺序:不设置包序号,不重排,不会发生队首阻塞 不跟踪连接状态:不必建立连接或重启状态机 不进行拥塞控制:不内置客户端或网络反馈机制</code></pre><h1 id="DNS"><a href="#DNS" class="headerlink" title="DNS"></a>DNS</h1><h2 id="DNS-协议是什么"><a href="#DNS-协议是什么" class="headerlink" title="DNS 协议是什么"></a>DNS 协议是什么</h2><pre><code>概念: DNS 是域名系统 (Domain Name System) 的缩写,提供的是一种主机名到 IP 地址的转换服务,就是我们常说的域名系统。它是一个由分层的 DNS 服务器组成的分布式数据库,是定义了主机如何查询这个分布式数据库的方式的应用层协议。能够使人更方便的访问互联网,而不用去记住能够被机器直接读取的 IP 数串。作用: 将域名解析为 IP 地址,客户端向 DNS 服务器(DNS 服务器有自己的 IP 地址)发送域名查询请求,DNS 服务器告知客户机 Web 服务器的 IP 地址。</code></pre><h2 id="DNS-同时使用-TCP-和-UDP-协议?"><a href="#DNS-同时使用-TCP-和-UDP-协议?" class="headerlink" title="DNS 同时使用 TCP 和 UDP 协议?"></a>DNS 同时使用 TCP 和 UDP 协议?</h2><pre><code>DNS占用53号端口,同时使用TCP和UDP协议。(1)在区域传输的时候使用TCP协议辅域名服务器会定时(一般3小时)向主域名服务器进行查询以便了解数据是否有变动。如有变动,会执行一次区域传送,进行数据同步。区域传送使用TCP而不是UDP,因为数据同步传送的数据量比一个请求应答的数据量要多得多。TCP是一种可靠连接,保证了数据的准确性。(2)在域名解析的时候使用UDP协议客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,用UDP传输即可。不用经过三次握手,这样DNS服务器负载更低,响应更快。理论上说,客户端也可以指定向DNS服务器查询时用TCP,但事实上,很多DNS服务器进行配置的时候,仅支持UDP查询包。</code></pre><h2 id="DNS-完整的查询过程"><a href="#DNS-完整的查询过程" class="headerlink" title="DNS 完整的查询过程"></a>DNS 完整的查询过程</h2><pre><code>DNS服务器解析域名的过程:首先会在浏览器的缓存中查找对应的IP地址,如果查找到直接返回,若找不到继续下一步将请求发送给本地DNS服务器,在本地域名服务器缓存中查询,如果查找到,就直接将查找结果返回,若找不到继续下一步本地DNS服务器向根域名服务器发送请求,根域名服务器会返回一个所查询域的顶级域名服务器地址本地DNS服务器向顶级域名服务器发送请求,接受请求的服务器查询自己的缓存,如果有记录,就返回查询结果,如果没有就返回相关的下一级的权威域名服务器的地址本地DNS服务器向权威域名服务器发送请求,域名服务器返回对应的结果本地DNS服务器将返回结果保存在缓存中,便于下次使用本地DNS服务器将返回结果返回给浏览器比如要查询 www.baidu.com 的 IP 地址,首先会在浏览器的缓存中查找是否有该域名的缓存,如果不存在就将请求发送到本地的 DNS 服务器中,本地DNS服务器会判断是否存在该域名的缓存,如果不存在,则向根域名服务器发送一个请求,根域名服务器返回负责 .com 的顶级域名服务器的 IP 地址的列表。然后本地 DNS 服务器再向其中一个负责 .com 的顶级域名服务器发送一个请求,负责 .com 的顶级域名服务器返回负责 .baidu 的权威域名服务器的 IP 地址列表。然后本地 DNS 服务器再向其中一个权威域名服务器发送一个请求,最后权威域名服务器返回一个对应的主机名的 IP 地址列表。</code></pre><h2 id="迭代查询与递归查询"><a href="#迭代查询与递归查询" class="headerlink" title="迭代查询与递归查询"></a>迭代查询与递归查询</h2><pre><code>实际上,DNS解析是一个包含迭代查询和递归查询的过程。1. 递归查询指的是查询请求发出后,域名服务器代为向下一级域名服务器发出请求,最后向用户返回查询的最终结果。使用递归 查询,用户只需要发出一次查询请求。2. 迭代查询指的是查询请求后,域名服务器返回单次查询的结果。下一级的查询由用户自己请求。使用迭代查询,用户需要发出 多次的查询请求。一般我们向本地 DNS 服务器发送请求的方式就是递归查询,因为我们只需要发出一次请求,然后本地 DNS 服务器返回给我 们最终的请求结果。而本地 DNS 服务器向其他域名服务器请求的过程是迭代查询的过程,因为每一次域名服务器只返回单次 查询的结果,下一级的查询由本地 DNS 服务器自己进行。</code></pre><h1 id="WebSocket"><a href="#WebSocket" class="headerlink" title="WebSocket"></a>WebSocket</h1><h2 id="对-WebSocket-的理解"><a href="#对-WebSocket-的理解" class="headerlink" title="对 WebSocket 的理解"></a>对 WebSocket 的理解</h2><pre><code>WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接, 并进行双向数据传输。WebSocket 的出现就解决了半双工通信的弊端。它最大的特点是:服务器可以向客户端主动推动消息,客户端也可以主动向服务器推送消息。</code></pre><h2 id="WebSocket-原理:"><a href="#WebSocket-原理:" class="headerlink" title="WebSocket 原理:"></a>WebSocket 原理:</h2><pre><code>客户端向 WebSocket 服务器通知(notify)一个带有所有接收者ID(recipients IDs)的事件(event),服务器接收后立即通知所有活跃的(active)客户端,只有ID在接收者ID序列中的客户端才会处理这个事件。</code></pre><h2 id="WebSocket-特点的如下:"><a href="#WebSocket-特点的如下:" class="headerlink" title="WebSocket 特点的如下:"></a>WebSocket 特点的如下:</h2><pre><code>支持双向通信,实时性更强可以发送文本,也可以发送二进制数据‘’建立在TCP协议之上,服务端的实现比较容易数据格式比较轻量,性能开销小,通信高效没有同源限制,客户端可以与任意服务器通信协议标识符是ws(如果加密,则为wss),服务器网址就是 URL与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。</code></pre><h2 id="时通讯的实现:短轮询、长轮询、SSE-和-WebSocket-间的区别?"><a href="#时通讯的实现:短轮询、长轮询、SSE-和-WebSocket-间的区别?" class="headerlink" title="时通讯的实现:短轮询、长轮询、SSE 和 WebSocket 间的区别?"></a>时通讯的实现:短轮询、长轮询、SSE 和 WebSocket 间的区别?</h2><pre><code>短轮询和长轮询的目的都是用于实现客户端和服务器端的一个即时通讯。**短轮询的基本思路**: 浏览器每隔一段时间向浏览器发送 http 请求,服务器端在收到请求后,不论是否有数据更新,都直接进行响应。这种方式实现的即时通信,本质上还是浏览器发送请求,服务器接受请求的一个过程,通过让客户端不断的进行请求,使得客户端能够模拟实时地收到服务器端的数据的变化。这种方式的优点是比较简单,易于理解。缺点是这种方式由于需要不断的建立 http 连接,严重浪费了服务器端和客户端的资源。当用户增加时,服务器端的压力就会变大,这是很不合理的。**长轮询的基本思路**:首先由客户端向服务器发起请求,当服务器收到客户端发来的请求后,服务器端不会直接进行响应,而是先将这个请求挂起,然后判断服务器端数据是否有更新。如果有更新,则进行响应,如果一直没有数据,则到达一定的时间限制才返回。客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。长轮询和短轮询比起来,它的优点是明显减少了很多不必要的 http 请求次数,相比之下节约了资源。长轮询的缺点在于,连接挂起也会导致资源的浪费。**SSE 的基本思想**:服务器使用流信息向服务器推送信息。严格地说,http 协议无法做到服务器主动推送信息。但是,有一种变通方法,就是服务器向客户端声明,接下来要发送的是流信息。也就是说,发送的不是一次性的数据包,而是一个数据流,会连续不断地发送过来。这时,客户端不会关闭连接,会一直等着服务器发过来的新的数据流,视频播放就是这样的例子。SSE 就是利用这种机制,使用流信息向浏览器推送信息。它基于 http 协议,目前除了 IE/Edge,其他浏览器都支持。它相对于前面两种方式来说,不需要建立过多的 http 请求,相比之下节约了资源。WebSocket 是 HTML5 定义的一个新协议议,与传统的 http 协议不同,该协议允许由服务器主动的向客户端推送信息。使用 WebSocket 协议的缺点是在服务器端的配置比较复杂。WebSocket 是一个全双工的协议,也就是通信双方是平等的,可以相互发送消息,而 SSE 的方式是单向通信的,只能由服务器端向客户端推送信息,如果客户端需要发送信息就是属于下一个 http 请求了。上面的四个通信协议,前三个都是基于HTTP协议的。对于这四种即使通信协议,从性能的角度来看:WebSocket > 长连接(SEE) > 长轮询 > 短轮询但是,我们如果考虑浏览器的兼容性问题,顺序就恰恰相反了:短轮询 > 长轮询 > 长连接(SEE) > WebSocket所以,还是要根据具体的使用场景来判断使用哪种方式。</code></pre><h1 id="缓存协议"><a href="#缓存协议" class="headerlink" title="缓存协议"></a>缓存协议</h1><h1 id="网络安全"><a href="#网络安全" class="headerlink" title="网络安全"></a>网络安全</h1><h1 id="网络性能优化"><a href="#网络性能优化" class="headerlink" title="网络性能优化"></a>网络性能优化</h1><h1 id="最重要的一点-输入-baidu-com-会发生什么"><a href="#最重要的一点-输入-baidu-com-会发生什么" class="headerlink" title="最重要的一点 输入 baidu.com 会发生什么"></a>最重要的一点 输入 baidu.com 会发生什么</h1>]]></content>
<categories>
<category> 网络知识 </category>
</categories>
<tags>
<tag> 网络知识 </tag>
</tags>
</entry>
<entry>
<title>CSS属性的计算过程</title>
<link href="/posts/83b2c1d6.html"/>
<url>/posts/83b2c1d6.html</url>
<content type="html"><![CDATA[<h1 id="CSS属性的计算过程"><a href="#CSS属性的计算过程" class="headerlink" title="CSS属性的计算过程"></a>CSS属性的计算过程</h1><h2 id="css属性值的计算过程"><a href="#css属性值的计算过程" class="headerlink" title="css属性值的计算过程"></a>css属性值的计算过程</h2><h3 id="什么是css属性值的计算过程"><a href="#什么是css属性值的计算过程" class="headerlink" title="什么是css属性值的计算过程"></a>什么是css属性值的计算过程</h3><pre><code>某个元素从所有的CSS元素没有值,到所有的CSS属性都有值的过程叫做计算过程也就是说就算只给div设置了一个背景颜色,不表示它没有其他属性值,它的所有css属性都有值</code></pre><h3 id="如何计算"><a href="#如何计算" class="headerlink" title="如何计算"></a>如何计算</h3><pre><code>分为四个步骤:(按顺序来,不能乱序) 1.确定声明值: 从作者样式表(我们所写的样式)和默认样式表(浏览器默认的样式)中找到没有冲突的样式,直接作为计算后的样式。 (类似于red类型的会转化成rbg) 2.层叠(css全称: 层叠样式表) 对有冲突的样式进行层叠,通过以下三个步骤: 1.比较重要性 重要性从高到底: 1.带有important的作者样式 2.带有important的默认样式 3.作者样式 4.默认样式 2.比较权重 对每个样式进行计算: sytye: 内敛为1 否则为0 id:id选择器的数量 属性:属性、类、伪类的数量 元素:元素 伪元素的数量 比如: .red {color : red} 0 0 1 0 h1 {color: red} 0 0 0 1 .div h1 .red 0 0 2 1 权重最大 优先级越高 3.比较源次序 如果权值相同,谁在下面谁优先级高 3.继承 对于仍然没有值的属性,若可以继承,则使用继承(可以去官网查看会不会继承,文字类大概率继承) 4.使用默认值 到目前还会没有值的(比如:background-color)会使用属性的默认值,每个属性都有默认值 比如background-color的默认值是transparent(透明)通过以上四个步骤 所有的css属性都会有值因为继承发生在第三步 而有些元素因为有默认值 且跟作者元素没有冲突 导致内部元素没有继承就是因为在某一部确定了值就不会进行下一步 比如:</code></pre><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="language-css"></span></span><br><span class="line"><span class="language-css"> <span class="selector-class">.box</span>{</span></span><br><span class="line"><span class="language-css"> <span class="attribute">color</span>: red</span></span><br><span class="line"><span class="language-css"> }</span></span><br><span class="line"><span class="language-css"></span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">'box'</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">a</span>></span>123<span class="tag"></<span class="name">a</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"></span><br></pre></td></tr></table></figure><pre><code>a标签并不会继承红色,因为a标签有默认样式颜色 所以第一步就确定了值如果第一步就确定了值 而没有继承值如a标签的颜色 可以使用color:inherit 将父元素属性值粘贴过来</code></pre><h2 id="实用技巧"><a href="#实用技巧" class="headerlink" title="实用技巧"></a>实用技巧</h2><h3 id="主动将某一样式设置为默认样式"><a href="#主动将某一样式设置为默认样式" class="headerlink" title="主动将某一样式设置为默认样式"></a>主动将某一样式设置为默认样式</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="language-css"></span></span><br><span class="line"><span class="language-css"> <span class="selector-class">.box</span>{</span></span><br><span class="line"><span class="language-css"> <span class="attribute">line-height</span>: initial;</span></span><br><span class="line"><span class="language-css"> }</span></span><br><span class="line"><span class="language-css"></span><span class="tag"></<span class="name">style</span>></span></span><br></pre></td></tr></table></figure><h3 id="想要清楚所有的浏览器默认样式-unset"><a href="#想要清楚所有的浏览器默认样式-unset" class="headerlink" title="想要清楚所有的浏览器默认样式 unset"></a>想要清楚所有的浏览器默认样式 unset</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="language-css"></span></span><br><span class="line"><span class="language-css"> <span class="selector-tag">body</span>,</span></span><br><span class="line"><span class="language-css"> <span class="selector-tag">body</span> *<span class="selector-pseudo">:not</span>(script){</span></span><br><span class="line"><span class="language-css"> <span class="attribute">all</span>: unset; </span></span><br><span class="line"><span class="language-css"> }</span></span><br><span class="line"><span class="language-css"></span><span class="tag"></<span class="name">style</span>></span></span><br></pre></td></tr></table></figure><h3 id="恢复默认属性-revert"><a href="#恢复默认属性-revert" class="headerlink" title="恢复默认属性 revert"></a>恢复默认属性 revert</h3><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">style</span>></span><span class="language-css"></span></span><br><span class="line"><span class="language-css"> <span class="selector-class">.default</span>{</span></span><br><span class="line"><span class="language-css"> <span class="attribute">all</span>: revert; </span></span><br><span class="line"><span class="language-css"> }</span></span><br><span class="line"><span class="language-css"></span><span class="tag"></<span class="name">style</span>></span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 前端学习 </category>
</categories>
<tags>
<tag> 前端学习 </tag>
</tags>
</entry>
<entry>
<title>Vue2数据劫持</title>
<link href="/posts/bd38f349.html"/>
<url>/posts/bd38f349.html</url>
<content type="html"><![CDATA[<h1 id="Vue2的数据劫持"><a href="#Vue2的数据劫持" class="headerlink" title="Vue2的数据劫持"></a>Vue2的数据劫持</h1><p>vue2的数据劫持使用Object.defineProperty对数据进行劫持,在数据变动时发布消息给订阅者,触发相应的监听回调。<br>以下是实现的代码 可以参考</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 先定义一个数据</span></span><br><span class="line"><span class="keyword">const</span> data = {</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'arafat'</span>,</span><br><span class="line"> <span class="attr">age</span>: <span class="number">18</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">// 对数据进行遍历</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i <span class="keyword">in</span> data){</span><br><span class="line"> <span class="keyword">let</span> value = data[i]</span><br><span class="line"> <span class="comment">// 依赖收集: 用于存储用到此数据的方法</span></span><br><span class="line"> <span class="keyword">let</span> arr = []</span><br><span class="line"> <span class="comment">// 通过Object.defineProperty对数据进行劫持</span></span><br><span class="line"> <span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(data , i, {</span><br><span class="line"> <span class="attr">get</span>: <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 是否有此函数 没有就添加</span></span><br><span class="line"> <span class="keyword">if</span>(!arr.<span class="title function_">includes</span>(<span class="variable language_">window</span>.<span class="property">__func</span>)){</span><br><span class="line"> arr.<span class="title function_">push</span>(<span class="variable language_">window</span>.<span class="property">__func</span>)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> value</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">set</span>: <span class="keyword">function</span> (<span class="params">newV</span>){</span><br><span class="line"> value = newV</span><br><span class="line"> <span class="comment">// 遍历订阅过的函数 并更新</span></span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> j <span class="keyword">of</span> arr){</span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> <span class="title function_">j</span>()</span><br><span class="line"> }<span class="keyword">catch</span>(err){</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(err)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">setName</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">'.name'</span>).<span class="property">textContent</span> = data.<span class="property">name</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">setAge</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">'.age'</span>).<span class="property">textContent</span> = data.<span class="property">age</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">setAll</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">'.all'</span>).<span class="property">textContent</span> = data.<span class="property">name</span> + <span class="string">" - "</span> + data.<span class="property">age</span></span><br><span class="line">}</span><br><span class="line"><span class="comment">// 因为需要依赖收集 所以执行时全局暴露函数 使用完清空</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">autoRun</span>(<span class="params">fn</span>){</span><br><span class="line"> <span class="variable language_">window</span>.<span class="property">__func</span> = fn</span><br><span class="line"> <span class="title function_">fn</span>()</span><br><span class="line"> <span class="variable language_">window</span>.<span class="property">__func</span> = <span class="literal">null</span></span><br><span class="line">}</span><br><span class="line"><span class="title function_">autoRun</span>(setName)</span><br><span class="line"><span class="title function_">autoRun</span>(setAge)</span><br><span class="line"><span class="title function_">autoRun</span>(setAll)</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> Vue2 </category>
</categories>
<tags>
<tag> Vue2 </tag>
<tag> 面试常问 </tag>
</tags>
</entry>
<entry>
<title>浏览器的渲染原理</title>
<link href="/posts/b5fc6f17.html"/>
<url>/posts/b5fc6f17.html</url>
<content type="html"><![CDATA[<h1 id="浏览器是如何渲染页面的?"><a href="#浏览器是如何渲染页面的?" class="headerlink" title="浏览器是如何渲染页面的?"></a>浏览器是如何渲染页面的?</h1><p>   当浏览器收到了html文档后,会产生一个渲染任务,并将其递给渲染主线程的消息队列。再事件循环机制的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程。</p><p>  整个渲染流程分为多个阶段:HTML解析,样式计算,布局,分层,绘制,分块,画。每个阶段都有明确的输入输出,上一个阶段的输出会成为下一个阶段的输入。<br>  这样渲染流程就形成了一套组织严密的生产流水线。</p><h2 id="渲染的第一步是解析HTML"><a href="#渲染的第一步是解析HTML" class="headerlink" title="渲染的第一步是解析HTML"></a>渲染的第一步是解析HTML</h2><p>  解析过程中遇到CSS解析CSS,遇到JS执行JS。为了提高解析效率,浏览器就在开始解析前,会启动一个解析的线程,率先下载HTML中的外部CSS文件和外部的JS文件。</p><p>  如果主线程解析到了link位置,此时外部的CSS文件还没下载解析好,主线程不会等待,继续解析后续HTML。这是因为下载和CSS的工作是在预解析线程中进行的。这就是CSS不会阻塞HTML的根本原因。</p><p>  如果主线程解析到了script位置,会停止解析HTML,转而等待JS文件下载好,并将全局代码解析执行完成后才能解析HTML。这是因为JS代码的执行过程可能会修改当前的DOM树,所有DOM树的生成必须暂停。这就是JS会阻塞HTML解析的根本原因。<br>(注意:</p><ul><li><ol><li> DOM解析和CSS解析是两个并行的进程,所以这也解释了为什么CSS加载不会阻塞DOM的解析。</li></ol></li><li><ol start="2"><li> 然而,由于Render Tree是依赖于DOM Tree和CSSOM Tree的,所以他必须等待到CSSOM Tree构建完成,也就是CSS资源加载完成(或者CSS资源加载失败)后,才能开始渲染。因此,CSS加载是会阻塞Dom的渲染的。</li></ol></li><li><ol start="3"><li>由于js可能会操作之前的Dom节点和css样式,因此浏览器会维持html中css和js的顺序。因此,样式表会在后面的js执行前先加载执行完毕。所以css会阻塞后面js的执行。<br>补充)</li></ol></li></ul><p>  第一步完成后会得到DOM树和CSSOM树,浏览器的默认样式,内部样式,外部样式,行内样式均会包含在CSSOM树中。</p><h2 id="第二步-样式计算"><a href="#第二步-样式计算" class="headerlink" title="第二步 样式计算"></a>第二步 样式计算</h2><p>  主线程会遍历得到DOM树,依次为树中的每个节点计算出它最终的样式,称之为computed style, 在这一过程中很多预设值都会变成绝对值,比如red会变成rgb(255,0,0),相对单位会变成绝对单位,比如em会变成px</p><p>  这一步完成后会得到一颗带有样式的DOM树。</p><h2 id="第三步是布局"><a href="#第三步是布局" class="headerlink" title="第三步是布局"></a>第三步是布局</h2><p>  布局阶段会遍历DOM树每个节点,计算每个节点的几何信息。列如节点的宽高,相对包含块的位置。<br>  大部分的时候DOM树和布局树并非一一对应。比如display:none的节点没有任何几何信息,因此不会生成布局树,还有伪元素选择器,虽然DOM树中不存在这些伪元素节点,但它们拥有几何信息,所以会生成刀布局树中。</p><p>(注意:</p><ul><li><ol><li>内容必须在行盒中</li></ol></li><li><ol start="2"><li>行盒和块盒不能相邻<div> <p>a</p> b <p>c</p></div>这种情况下dom树结构 div 布局树元素 div p元素 b p元素 p元素 匿名块盒 p元素 a c 匿名行盒 b 匿名行盒 a c </li></ol></li></ul><h2 id="第四步是分层"><a href="#第四步是分层" class="headerlink" title="第四步是分层"></a>第四步是分层</h2><p>  主线程会使用一套复杂的策略对整个布局树进行分层。分层的好处在于将来某一个层改变后,仅会对该层进行后续处理,从而提升效率。</p><p>比如:滚动条,transform,opacity等样式或多或少的影响分层结构,可以通过will-change属性更大程度的影响分层结果。</p><p>(注意:分层不能乱用,如果某个区域变化很多,出现了渲染问题才会需要分层)</p><h2 id="第五步是绘制"><a href="#第五步是绘制" class="headerlink" title="第五步是绘制"></a>第五步是绘制</h2><p>  主线程会为每一个层单独产生绘制指令集,用于描述这一层的内容该如何画出来。</p><h2 id="第六步分块"><a href="#第六步分块" class="headerlink" title="第六步分块"></a>第六步分块</h2><p>  完成绘制后,主线程将每个图层的绘制信息提交给合成流程,剩余工作将由合成线程完成。<br>合成线程首先对每个图层进行分块,将其划分为更多的小区域。<br>它会从线程池中拿取多个线程来完成分块工作。</p><h2 id="第七步光栅化"><a href="#第七步光栅化" class="headerlink" title="第七步光栅化"></a>第七步光栅化</h2><p>合成线程会将块信息交给GPU进程,以极高的速度完成光栅化。<br>GPU进程会开启多个线程完成光栅化,并且优先处理靠近视口区域的块。<br>光栅化的结果,就是一块一块的位图。</p><h2 id="最后一步-画"><a href="#最后一步-画" class="headerlink" title="最后一步 画"></a>最后一步 画</h2><p>合成线程拿到每个层,每个块的位图后,生成一个个指引信息。<br>之心会标识初每个位图应该画到屏幕的哪个位置,以及考虑刀旋转缩放等变形。<br>变形发生在合成线程,与渲染主线程无关,这既是transform效率高的本质原因。<br>合成线程会把quad提交给GPU进程,由GPU进程产生系统调用,提交给GPU硬件,完成最终屏幕的呈现。</p>]]></content>
<categories>
<category> 浏览器的渲染原理 </category>
</categories>
<tags>
<tag> 浏览器的渲染原理 </tag>
</tags>
</entry>
<entry>
<title>Webpack优化教程</title>
<link href="/posts/ca484621.html"/>
<url>/posts/ca484621.html</url>
<content type="html"><![CDATA[<h1 id="webpack优化"><a href="#webpack优化" class="headerlink" title="webpack优化"></a>webpack优化</h1><p>我们会从以下角度来进行优化:<br> 1.提升开发体验<br> 2.提升打包构建速度<br> 3.减少代码体积<br> 4.优化代码运行性能</p><h1 id="提升开发体验"><a href="#提升开发体验" class="headerlink" title="提升开发体验"></a>提升开发体验</h1><h2 id="SourceMap"><a href="#SourceMap" class="headerlink" title="SourceMap"></a>SourceMap</h2><p> webpack编译后的所有 css 和 js 合并成了一个文件,并且多了其他代码。此时如果代码运行出错那么提示代码错误位置我们是看不懂的。一旦将来开发代码文件很多,那么很难去发现错误出现在哪里。</p><p> 这时我们可以通过SourceMap(源代码映射)是一个用来生成源代码与构建后代码一一映射的文件的方案。<br> 它会生成一个 xxx.map 文件,里面包含源代码和构建后代码每一行、每一列的映射关系。当构建后代码出错了,会通过 xxx.map 文件,从构建后代码出错位置找到映射后源代码出错位置,从而让浏览器提示源代码文件出错位置,帮助我们更快的找到错误根源。</p><h1 id="提升打包构建速度"><a href="#提升打包构建速度" class="headerlink" title="提升打包构建速度"></a>提升打包构建速度</h1><h2 id="HotModuleReplacement"><a href="#HotModuleReplacement" class="headerlink" title="HotModuleReplacement"></a>HotModuleReplacement</h2><p> 开发时我们修改了其中一个模块代码,Webpack 默认会将所有模块全部重新打包编译,速度很慢。<br> 所以我们需要做到修改某个模块代码,就只有这个模块代码需要重新打包编译,其他模块不变,这样打包速度就能很快。</p><p> HotModuleReplacement(HMR/热模块替换):在程序运行中,替换、添加或删除模块,而无需重新加载整个页面。</p><h2 id="OneOf"><a href="#OneOf" class="headerlink" title="OneOf"></a>OneOf</h2><p> 打包时每个文件都会经过所有 loader 处理,虽然因为 test 正则原因实际没有处理上,但是都要过一遍。比较慢。<br> 这时可以使用OneOf 顾名思义就是只能匹配上一个 loader, 剩下的就不匹配了。</p><h2 id="Include-Exclude"><a href="#Include-Exclude" class="headerlink" title="Include/Exclude"></a>Include/Exclude</h2><p> 开发时我们需要使用第三方的库或插件,所有文件都下载到 node_modules 中了。而这些文件是不需要编译可以直接使用的。<br> 所以我们在对 js 文件处理时,要排除 node_modules 下面的文件。</p><p> include<br> 包含,只处理 xxx 文件<br> exclude<br> 排除,除了 xxx 文件以外其他文件都处理</p><h2 id="Cache"><a href="#Cache" class="headerlink" title="Cache"></a>Cache</h2><p> 每次打包时 js 文件都要经过 Eslint 检查 和 Babel 编译,速度比较慢。<br> 我们可以缓存之前的 Eslint 检查 和 Babel 编译结果,这样第二次打包时速度就会更快了</p><h2 id="Thead"><a href="#Thead" class="headerlink" title="Thead"></a>Thead</h2><p> 当项目越来越庞大时,打包速度越来越慢,甚至于需要一个下午才能打包出来代码。这个速度是比较慢的。<br> 我们想要继续提升打包速度,其实就是要提升 js 的打包速度,因为其他文件都比较少。<br> 而对 js 文件处理主要就是 eslint 、babel、Terser 三个工具,所以我们要提升它们的运行速度。<br> 我们可以开启多进程同时处理 js 文件,这样速度就比之前的单进程打包更快了。</p><p> 多进程打包:开启电脑的多个进程同时干一件事,速度更快。<br> 需要注意:请仅在特别耗时的操作中使用,因为每个进程启动就有大约为 600ms 左右开销。</p><h1 id="减少代码体积"><a href="#减少代码体积" class="headerlink" title="减少代码体积"></a>减少代码体积</h1><h2 id="Tree-Shaking"><a href="#Tree-Shaking" class="headerlink" title="Tree Shaking"></a>Tree Shaking</h2><p> Webpack 已经默认开启了这个功能,通常用于移除 JavaScript 中的没有使用上的代码。</p><h2 id="Babel"><a href="#Babel" class="headerlink" title="Babel"></a>Babel</h2><p> Babel 为编译的每个文件都插入了辅助代码,使代码体积过大!<br> Babel 对一些公共方法使用了非常小的辅助代码,比如 _extend。默认情况下会被添加到每一个需要它的文件中。<br> 你可以将这些辅助代码作为一个独立模块,来避免重复引入。</p><p> @babel/plugin-transform-runtime: 禁用了 Babel 自动对每个文件的 runtime 注入,而是引入 @babel/plugin-transform-runtime 并且使所有辅助代码从这里引用。</p><h2 id="Image-Minimizer"><a href="#Image-Minimizer" class="headerlink" title="Image Minimizer"></a>Image Minimizer</h2><p> 开发如果项目中引用了较多图片,那么图片体积会比较大,将来请求速度比较慢。<br> 我们可以对图片进行压缩,减少图片体积。<br> 注意:如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。</p><p> image-minimizer-webpack-plugin: 用来压缩图片的插件</p><h1 id="优化代码运行性能"><a href="#优化代码运行性能" class="headerlink" title="优化代码运行性能"></a>优化代码运行性能</h1><h2 id="Code-Split"><a href="#Code-Split" class="headerlink" title="Code Split"></a>Code Split</h2><p> 打包代码时会将所有 js 文件打包到一个文件中,体积太大了。我们如果只要渲染首页,就应该只加载首页的 js 文件,其他文件不应该加载。<br> 所以我们需要将打包生成的文件进行代码分割,生成多个 js 文件,渲染哪个页面就只加载某个 js 文件,这样加载的资源就少,速度就更快。</p><p> 代码分割(Code Split)主要做了两件事:<br> 1.分割文件:将打包生成的文件进行分割,生成多个 js 文件。<br> 2.按需加载:需要哪个文件就加载哪个文件。</p><h2 id="Preload-Prefetch"><a href="#Preload-Prefetch" class="headerlink" title="Preload / Prefetch"></a>Preload / Prefetch</h2><p> 用处:用户点击按钮时才加载这个资源的,如果资源体积很大,那么用户会感觉到明显卡顿效果。<br> 我们想在浏览器空闲时间,加载后续需要使用的资源。我们就需要用上 Preload 或 Prefetch 技术。</p><p> Preload:告诉浏览器立即加载资源。<br> Prefetch:告诉浏览器在空闲时才开始加载资源。</p><p> 它们共同点:<br> 都只会加载资源,并不执行。<br> 都有缓存。</p><p> 它们区别:<br> Preload加载优先级高,Prefetch加载优先级低。<br> Preload只能加载当前页面需要使用的资源,Prefetch可以加载当前页面资源,也可以加载下一个页面需要使用的资源。</p><p> 总结:<br> 当前页面优先级高的资源用 Preload 加载。<br> 下一个页面需要使用的资源用 Prefetch 加载。</p><p> 它们的问题:兼容性较差。<br> Preload 相对于 Prefetch 兼容性好一点。</p><h2 id="Network-Cache"><a href="#Network-Cache" class="headerlink" title="Network Cache"></a>Network Cache</h2><p> 将来开发时我们对静态资源会使用缓存来优化,这样浏览器第二次请求资源就能读取缓存了,速度很快。<br> 但是这样的话就会有一个问题, 因为前后输出的文件名是一样的,都叫 main.js,一旦将来发布新版本,因为文件名没有变化导致浏览器会直接读取缓存,不会加载新资源,项目也就没法更新了。</p><p> 所以我们从文件名入手,确保更新前后文件名不一样,这样就可以做缓存了。</p><p> 什么是Network Cache?<br> 它们都会生成一个唯一的 hash 值。</p><pre><code>fullhash(webpack4 是 hash)每次修改任何一个文件,所有文件名的 hash 至都将改变。所以一旦修改了任何一个文件,整个项目的文件缓存都将失效。chunkhash根据不同的入口文件(Entry)进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。我们 js 和 css 是同一个引入,会共享一个 hash 值。contenthash根据文件内容生成 hash 值,只有文件内容变化了,hash 值才会变化。所有文件 hash 值是独享且不同的</code></pre><h2 id="PWA"><a href="#PWA" class="headerlink" title="PWA"></a>PWA</h2><p> 开发 Web App 项目,项目一旦处于网络离线情况,就没法访问了。<br> 我们希望给项目提供离线体验。</p><p> 是什么PWA?<br> 渐进式网络应用程序(progressive web application - PWA):是一种可以提供类似于 native app(原生应用程序) 体验的 Web App 的技术。<br> 其中最重要的是,在 离线(offline) 时应用程序能够继续运行功能。<br> 内部通过 Service Workers 技术实现的。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><pre><code>我们从 4 个角度对 webpack 和代码进行了优化:提升开发体验使用 Source Map 让开发或上线时代码报错能有更加准确的错误提示。提升 webpack 提升打包构建速度使用 HotModuleReplacement 让开发时只重新编译打包更新变化了的代码,不变的代码使用缓存,从而使更新速度更快。使用 OneOf 让资源文件一旦被某个 loader 处理了,就不会继续遍历了,打包速度更快。使用 Include/Exclude 排除或只检测某些文件,处理的文件更少,速度更快。使用 Cache 对 eslint 和 babel 处理的结果进行缓存,让第二次打包速度更快。使用 Thead 多进程处理 eslint 和 babel 任务,速度更快。(需要注意的是,进程启动通信都有开销的,要在比较多代码处理时使用才有效果)减少代码体积使用 Tree Shaking 剔除了没有使用的多余代码,让代码体积更小。使用 @babel/plugin-transform-runtime 插件对 babel 进行处理,让辅助代码从中引入,而不是每个文件都生成辅助代码,从而体积更小。使用 Image Minimizer 对项目中图片进行压缩,体积更小,请求速度更快。(需要注意的是,如果项目中图片都是在线链接,那么就不需要了。本地项目静态图片才需要进行压缩。)优化代码运行性能使用 Code Split 对代码进行分割成多个 js 文件,从而使单个文件体积更小,并行加载 js 速度更快。并通过 import 动态导入语法进行按需加载,从而达到需要使用时才加载该资源,不用时不加载资源。使用 Preload / Prefetch 对代码进行提前加载,等未来需要使用时就能直接使用,从而用户体验更好。使用 Network Cache 能对输出资源文件进行更好的命名,将来好做缓存,从而用户体验更好。使用 Core-js 对 js 进行兼容性处理,让我们代码能运行在低版本浏览器。使用 PWA 能让代码离线也能访问,从而提升用户体验。</code></pre>]]></content>
<categories>
<category> 前端开发 </category>
</categories>
<tags>
<tag> Webpack基础 </tag>
</tags>
</entry>
<entry>
<title>Vue2面试题常问面试题</title>
<link href="/posts/f50a3637.html"/>
<url>/posts/f50a3637.html</url>
<content type="html"><![CDATA[<h1 id="对MVVM的理解:"><a href="#对MVVM的理解:" class="headerlink" title="对MVVM的理解:"></a>对MVVM的理解:</h1><p>  MVVM 由 Model、View、ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来;ViewModel 是一个同步View 和 Model的对象。<br>  在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。<br>  ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。</p><h1 id="Vue数据双向绑定的原理:"><a href="#Vue数据双向绑定的原理:" class="headerlink" title="Vue数据双向绑定的原理:"></a>Vue数据双向绑定的原理:</h1><p>  实现mvvm的数据双向绑定,是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来给各个属性添加setter,getter并劫持监听,在数据变动时发布消息给订阅者,触发相应的监听回调。就必须要实现以下几点:<br>1、实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并通知订阅者<br>2、实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,根据指令模板替换数据,以及绑定相应的更新函数<br>3、实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图<br><img src="https://img01.anzhiy.cn/useruploads/0/2023/04/26/6448d2fbb605e.png"></p><h1 id="Vue响应式原理"><a href="#Vue响应式原理" class="headerlink" title="Vue响应式原理"></a>Vue响应式原理</h1><p>  Object.defineProperty 为对象中的每一个属性,设置get和set方法,每个声明的属性,都会有一个专属的依赖收集器 subs,当页面使用到某个属性时,触发ObjectdefineProperty get函数,页面的watcher就会被放到属性的依赖收集器subs中,在数据变化时,通知更新;<br>当数据改变的时候,会触发Object.defineProperty - set函数,数据会遍历自己的 依赖收集器 subs,逐个通知 watcher,视图开始更新;</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = {</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'aaaa'</span></span><br><span class="line">}</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(obj, <span class="string">'name'</span>, {</span><br><span class="line"><span class="attr">configurable</span>: <span class="literal">true</span>,</span><br><span class="line"><span class="attr">enumerable</span>: <span class="literal">true</span>,</span><br><span class="line"><span class="attr">get</span>: <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`你访问了obj.name属性哦`</span>);</span><br><span class="line"><span class="keyword">return</span> value;</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">set</span>: <span class="keyword">function</span> (<span class="params">val</span>) {</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`设置obj.name的值为:<span class="subst">${val}</span>`</span>)</span><br><span class="line">}</span><br><span class="line">})</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(obj.<span class="property">name</span>)</span><br><span class="line">obj.<span class="property">name</span> = <span class="string">'bbbb'</span></span><br></pre></td></tr></table></figure><h1 id="vue中组件的data为什么是一个函数?而new-Vue-实例里,data-可以直接是一个对象"><a href="#vue中组件的data为什么是一个函数?而new-Vue-实例里,data-可以直接是一个对象" class="headerlink" title="vue中组件的data为什么是一个函数?而new Vue 实例里,data 可以直接是一个对象"></a>vue中组件的data为什么是一个函数?而new Vue 实例里,data 可以直接是一个对象</h1><p>  Vue的data数据其实是Vue原型上的属性,数据存在于内存当中。Vue为了保证每个实例上的data数据的独立性,规定了必须使用函数,而不是对象。因为使用对象的话,每个实例(组件)上使用的data数据是相互影响的,这当然就不是我们想要的了。对象是对于内存地址的引用,直接定义个对象的话组件之间都会使用这个对象,这样会造成组件之间数据相互影响。使用函数后,使用的是data()函数,data()函数中的this指向的是当前实例本身,就不会相互影响了。而 new Vue 的实例,是不会被复用的,因此不存在引用对象的问题。</p><h1 id="vue中created与mounted区别"><a href="#vue中created与mounted区别" class="headerlink" title="vue中created与mounted区别"></a>vue中created与mounted区别</h1><p>  在created阶段,实例已经被初始化,但是还没有挂载至el上,所以我们无法获取到对应的节点,但是此时我们是可以获取到vue中data与methods中的数据的;<br>  在mounted阶段,vue的template成功挂载在$el中,此时一个完整的页面已经能够显示在浏览器中,所以在这个阶段,可以调用节点了;</p><h1 id="Vue中computed与method的区别"><a href="#Vue中computed与method的区别" class="headerlink" title="Vue中computed与method的区别"></a>Vue中computed与method的区别</h1><p>  相同点:<br>    如果作为模板的数据显示,二者能实现响应的功能,唯一不同的是methods定义的方法需要执行<br>  不同点:</p><ul><li>1.computed 会基于响应数据缓存,methods不会缓存;</li><li>2.diff之前先看data里的数据是否发生变化,如果没有变化computed的方法不会执行,但methods里的方法会执行</li><li>3.computed是属性调用,而methods是函数调用</li></ul><h1 id="虚拟DOM中key的作用"><a href="#虚拟DOM中key的作用" class="headerlink" title="虚拟DOM中key的作用"></a>虚拟DOM中key的作用</h1><p>  简单的说:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。<br>  复杂的说:当状态中的数据发生了变化时,vue会根据【新数据】生成【新的虚拟DOM】,随后<br>进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:</p><p>  旧虚拟DOM中找到了与新虚拟DOM相同的key</p><ul><li>1.若虚拟DOM中的内容没有变,直接使用之前的真是DOM</li><li>2.若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM</li><li>3.旧虚拟DOM中未找到与新虚拟DOM相同的key</li><li>4.根据数据创建新的真实DOM,随后渲染到页面</li></ul><p>  用index作为key可能会引发的问题<br>    若对数据进行:逆序添加/逆序删除等破坏顺序的操作,会产生没有必要的真实DOM更新,界面效果虽然没有问题,但是数据过多的话,会效率过低;<br>    如果结构中还包含输入类的DOM,会产生错误DOM更新,界面有问题;<br>    注意!如果不存在对数据的逆序操作,仅用于渲染表用于展示,使用index作为key是没有问题的。</p><h1 id="Vue中watch用法详解"><a href="#Vue中watch用法详解" class="headerlink" title="Vue中watch用法详解"></a>Vue中watch用法详解</h1><p>  在vue中,使用watch来监听数据的变化;</p><ul><li>1.监听的数据后面可以写成对象形式,包含handler方法,immediate和deep。</li><li>2.immediate表示在watch中首次绑定的时候,是否执行handler,值为true则表示在watch中声明的时候,就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化的时候才执行handler。</li><li>3.当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听。</li></ul><h1 id="vue中对mixins的理解和使用"><a href="#vue中对mixins的理解和使用" class="headerlink" title="vue中对mixins的理解和使用"></a>vue中对mixins的理解和使用</h1><p>  将组件的公共逻辑或者配置提取出来,哪个组件需要用到时,直接将提取的这部分混入到组件内部即可。这样既可以减少代码冗余度,也可以让后期维护起来更加容易。<br>  这里需要注意的是:提取的是逻辑或配置,而不是HTML代码和CSS代码。其实大家也可以换一种想法,mixin就是组件中的组件,Vue组件化让我们的代码复用性更高,那么组件与组件之间还有重复部分,我们使用Mixin在抽离一遍。<br>  可以理解为minins就是组件的组件 让可复用的组件提取出来供大家使用</p><p>   定义mixin也非常简单,它就是一个对象而已,只不过这个对象里面可以包含Vue组件中的一些常见配置,如data、methods、created等等。然后引入就可以了 并且各个组件引入是独立的,A组件修改了mixin的值并不会影响B组件的mixin</p><h1 id="vue中的插槽"><a href="#vue中的插槽" class="headerlink" title="vue中的插槽"></a>vue中的插槽</h1><h2 id="定义:"><a href="#定义:" class="headerlink" title="定义:"></a>定义:</h2><p>  插槽的使用过程其实是抽取共性、保留不同;<br>  我们会将共同的元素、内容依然在组件内进行封装;<br>  同时会将不同的元素使用slot作为占位,让外部决定到底显示什么样的元素;</p><p>  使用方法:</p><ul><li>Vue中将 <slot> 元素作为承载分发内容的出口;</li><li>在封装组件中,使用特殊的元素<slot>就可以为封装组件开启一个插槽;</li><li>该插槽插入什么内容取决于父组件如何使用;</li></ul><p>  默认插槽:<br>  当然这个默认的内容只会在没有提供插入的内容时,才会显示;</p><p>  具名插槽:<br>  当有多个插槽,并且想要插槽对应的显示使用具名插槽;</p><p>  作用域<br>  那就是在父组件中访问子组件的数据,或者从数据流向的角度来讲就是将子组件的数据传递到父组件。</p><h1 id="为何Vue采用异步渲染"><a href="#为何Vue采用异步渲染" class="headerlink" title="为何Vue采用异步渲染"></a>为何Vue采用异步渲染</h1><p>  vue是组件级更新,组件内有数据变化时,该组件就会更新。例:this.a = 1、this.b=2(同一个watcher)</p><ul><li>原因:如果不采用异步更新,那么每次更新数据都会对当前组件进行重新渲染。所以为了性能考虑,Vue 会在本轮数据更新后,再去异步更新视图。而不是每当有数据更新,就立即更新视图。</li></ul><p>  过程:</p><ul><li>Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop) 中 观察到数据变化的 watcher 推送进这个队列。</li><li>如果这个watcher被触发多次,只会被推送到队列一次。这种缓冲行为可以有效的去掉重复数据,避免不必要的计算和Dom操作。</li><li>而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新。</li></ul><p>  源码解析:</p><ul><li>数据变化时,通过notify通知watcher进行更新操作;</li><li>通过subs[i].update依次调用watcher的update(未更新视图);</li><li>将watcher放到队列中,在queueWatcher会根据watcher的id进行去重(多个属性依赖一个watcher),如果队列中没有该watcher就会将该watcher添加到队列中(未更新视图);</li><li>通过nextTick异步执行flushSchedulerQueue方法刷新watcher队列(更新视图);</li></ul><h1 id="Vue-的异步更新机制是如何实现的?"><a href="#Vue-的异步更新机制是如何实现的?" class="headerlink" title="Vue 的异步更新机制是如何实现的?"></a>Vue 的异步更新机制是如何实现的?</h1><p>Vue 的异步更新机制的核心是利用了浏览器的异步任务队列来实现的,首选微任务队列,宏任务队列次之。</p><p>当响应式数据更新后,会调用 dep.notify 方法,通知 dep 中收集的 watcher 去执行 update 方法,watcher.update 将 watcher 自己放入一个 watcher 队列(全局的 queue 数组)。</p><p>然后通过 nextTick 方法将一个刷新 watcher 队列的方法(flushSchedulerQueue)放入一个全局的 callbacks 数组中。</p><p>如果此时浏览器的异步任务队列中没有一个叫 flushCallbacks 的函数,则执行 timerFunc 函数,将 flushCallbacks 函数放入异步任务队列。如果异步任务队列中已经存在 flushCallbacks 函数,等待其执行完成以后再放入下一个 flushCallbacks 函数。</p><p>flushCallbacks 函数负责执行 callbacks 数组中的所有 flushSchedulerQueue 函数。</p><p>flushSchedulerQueue 函数负责刷新 watcher 队列,即执行 queue 数组中每一个 watcher 的 run 方法,从而进入更新阶段,比如执行组件更新函数或者执行用户 watch 的回调函数。</p><h1 id="nextTick的理解"><a href="#nextTick的理解" class="headerlink" title="$nextTick的理解"></a>$nextTick的理解</h1><h2 id="用法:"><a href="#用法:" class="headerlink" title="用法:"></a>用法:</h2><p>在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。<br>为什么?<br>Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。<br>所以为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用。</p><h2 id="使用场景"><a href="#使用场景" class="headerlink" title="使用场景"></a>使用场景</h2><p>在你更新完数据后,需要及时操作渲染好的 DOM时</p><h1 id="Vue除了核心功能默认内置的指令-,Vue-也允许注册自定义指令。"><a href="#Vue除了核心功能默认内置的指令-,Vue-也允许注册自定义指令。" class="headerlink" title="Vue除了核心功能默认内置的指令 ,Vue 也允许注册自定义指令。"></a>Vue除了核心功能默认内置的指令 ,Vue 也允许注册自定义指令。</h1><p>自定义指令是用来操作DOM的。尽管Vue推崇数据驱动视图的理念,但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和扩展,不仅可用于定义任何的DOM操作,并且是可复用的。</p><p>添加自定义指令的两种方式:</p><p>全局指令: 通过 Vue.directive() 函数注册一个全局的指令。<br>局部指令:通过组件的 directives 属性,对该组件添加一个局部的指令。</p><h2 id="使用场景:"><a href="#使用场景:" class="headerlink" title="使用场景:"></a>使用场景:</h2><p>需求:有些网站图片的加载做得非常优雅,在图片未完成加载前,用随机的背景色占位,图片加载完成后才直接渲染出来。用自定义指令可以非常方便的实现这个功能。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><div id=<span class="string">"app"</span> v-image = <span class="string">"item "</span> v-<span class="keyword">for</span>=<span class="string">"item in imageList"</span>></div></span><br><span class="line"><span class="language-xml"><span class="tag"><<span class="name">script</span>></span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="title class_">Vue</span>.<span class="title function_">directive</span>(<span class="string">"image"</span>, {</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="attr">inserted</span>: <span class="keyword">function</span>(<span class="params">el,binding</span>){</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="keyword">var</span> color = <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>,<span class="title function_">random</span>()*<span class="number">1000000</span>)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> el.<span class="property">style</span>.<span class="property">backgroundColor</span> = <span class="string">"#"</span> + color</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="keyword">var</span> img = <span class="keyword">new</span> <span class="title class_">Image</span>()</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> img.<span class="property">src</span> = binding.<span class="property">vaule</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> img.<span class="property">onload</span> = <span class="keyword">function</span>(<span class="params"></span>){ </span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> el.<span class="property">style</span>.<span class="property">backgroundImage</span> = “<span class="title function_">url</span>(” + binding.<span class="property">vaule</span> + <span class="string">")"</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> }</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> }</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> })</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="keyword">new</span> <span class="title class_">Vue</span>({</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="attr">el</span>: <span class="string">"#app"</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="attr">data</span>: {</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="attr">imageList</span>: [</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> {</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="attr">url</span>: <span class="string">"http://consumer-img.huawei.com/content/dam/huawei-cbg-site/greate-china/cn/mkt/homepage/section4/home-s4-p10-plus.jpg"</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> },</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> {</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="attr">url</span>: <span class="string">"http://consumer-img.huawei.com/content/dam/huawei-cbg-site/greate-china/cn/mkt/homepage/section4/home-s4-watch2-pro-banner.jpg"</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> },</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> {</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> <span class="attr">url</span>: <span class="string">"http://consumer-img.huawei.com/content/dam/huawei-cbg-site/en/mkt/homepage/section4/home-s4-matebook-x.jpg"</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> }</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> ]</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> }</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> })</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"> </span><span class="tag"></<span class="name">script</span>></span></span></span><br></pre></td></tr></table></figure><h1 id="Vue-set-改变数组和对象中的属性"><a href="#Vue-set-改变数组和对象中的属性" class="headerlink" title="Vue.set 改变数组和对象中的属性"></a>Vue.set 改变数组和对象中的属性</h1><p>在一个组件实例中,只有在data里初始化的数据才是响应的,Vue不能检测到对象属性的添加或删除,没有在data里声明的属性不是响应的,所以数据改变了但是不会在页面渲染;<br>解决办法:<br>使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上</p><h1 id="说说vue的生命周期的理解"><a href="#说说vue的生命周期的理解" class="headerlink" title="说说vue的生命周期的理解"></a>说说vue的生命周期的理解</h1><p><img src="https://img01.anzhiy.cn/useruploads/0/2023/04/26/6448e2b2c5272.png"></p><h1 id="vue通信方式:"><a href="#vue通信方式:" class="headerlink" title="vue通信方式:"></a>vue通信方式:</h1><ul><li>1、父组件向子组件传递数据 props</li><li>2.子组件向父组件传递数据($emit的用法)</li><li>3.兄弟组件通信(通过父组件parent)</li><li>4、ref / $refs</li><li>5、eventBus事件总线($emit / $on)</li><li>6、依赖注入(provide / inject)</li><li>7.$parent / $children</li><li>10.vuex</li></ul>]]></content>
<categories>
<category> 面试类 </category>
</categories>
<tags>
<tag> Vue2 </tag>
<tag> 面试常问 </tag>
</tags>
</entry>
<entry>
<title>js设计模式-策略模式</title>
<link href="/posts/b0b32b9.html"/>
<url>/posts/b0b32b9.html</url>
<content type="html"><;</span><br><span class="line">};</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">annualBonus</span>(<span class="string">'A'</span>,<span class="number">10000</span>)); <span class="comment">// 40000</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>js设计模式-观察者模式</title>
<link href="/posts/f4a69292.html"/>
<url>/posts/f4a69292.html</url>
<content type="html"><![CDATA[<h1 id="定义:"><a href="#定义:" class="headerlink" title="定义:"></a>定义:</h1><p>  在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。</p><h1 id="观察者模式和发布-订阅模式一样么?"><a href="#观察者模式和发布-订阅模式一样么?" class="headerlink" title="观察者模式和发布-订阅模式一样么?"></a>观察者模式和发布-订阅模式一样么?</h1><p>  不一样!<br>  观察者模式会直接通知订阅者<br>  发布-订阅不会直接通知订阅者,而是通过第三个角色事件调度中心来实现通知订阅者</p><h1 id="例子:"><a href="#例子:" class="headerlink" title="例子:"></a>例子:</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">function</span> <span class="title function_">SellHome</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">userList</span> = [];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="title class_">SellHome</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">attach</span> = <span class="keyword">function</span> (<span class="params">msg</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'11'</span>, <span class="variable language_">this</span>);</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">userList</span>.<span class="title function_">forEach</span>(<span class="function"><span class="params">u</span> =></span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'hh'</span>, u.<span class="property">name</span>+<span class="string">''</span>+msg);</span><br><span class="line"> });</span><br><span class="line">};</span><br><span class="line"><span class="title class_">SellHome</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">listen</span> = <span class="keyword">function</span> (<span class="params">user</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'22'</span>, <span class="variable language_">this</span>);</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">userList</span>.<span class="title function_">push</span>(user);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> u1 = {</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'小明'</span>,</span><br><span class="line"> <span class="attr">age</span>: <span class="number">20</span></span><br><span class="line">};</span><br><span class="line"><span class="keyword">const</span> u2 = {</span><br><span class="line"> <span class="attr">name</span>: <span class="string">'小红'</span>,</span><br><span class="line"> <span class="attr">age</span>: <span class="number">18</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> s = <span class="keyword">new</span> <span class="title class_">SellHome</span>();</span><br><span class="line">s.<span class="title function_">listen</span>(u1);</span><br><span class="line">s.<span class="title function_">listen</span>(u2);</span><br><span class="line"></span><br><span class="line">s.<span class="title function_">attach</span>(<span class="string">'吃饭啦'</span>);</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>js设计模式-装饰器模式</title>
<link href="/posts/f55bc382.html"/>
<url>/posts/f55bc382.html</url>
<content type="html"><![CDATA[<h1 id="装饰器模式"><a href="#装饰器模式" class="headerlink" title="装饰器模式"></a>装饰器模式</h1><p>  为对象添加新功能,不改变其原有的结构和功能,和适配器模式不一样,适配器模式是原有的不能用了,而装饰器模式是原来的还能用,不过给增加一些功能。<br>  比如: 手机壳,用来给手机美观,保护,防滑等等</p><h1 id="例子:"><a href="#例子:" class="headerlink" title="例子:"></a>例子:</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Circle</span> {</span><br><span class="line"> <span class="title function_">draw</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"画一个圆形"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Decorator</span> {</span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">circle</span>){</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">circle</span> = circle;</span><br><span class="line"> }</span><br><span class="line"> <span class="title function_">draw</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">circle</span>.<span class="title function_">draw</span>();</span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">setRedBorder</span>(<span class="variable language_">this</span>.<span class="property">circle</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="title function_">setRedBorder</span>(<span class="params">circle</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"设置红色边框"</span>)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 测试代码</span></span><br><span class="line"><span class="keyword">let</span> circle = <span class="keyword">new</span> <span class="title class_">Circle</span>();</span><br><span class="line">circle.<span class="title function_">draw</span>()</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> dec = <span class="keyword">new</span> <span class="title class_">Decorator</span>(circle);</span><br><span class="line">dec.<span class="title function_">draw</span>();</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>js设计模式-适配器模式</title>
<link href="/posts/9b47c56e.html"/>
<url>/posts/9b47c56e.html</url>
<content type="html"><![CDATA[<h1 id="什么是适配器模式"><a href="#什么是适配器模式" class="headerlink" title="什么是适配器模式"></a>什么是适配器模式</h1><p>  适配器模式:将一个类(对象)的接口(方法或属性)转化成客户希望的另外一个接口(方法或属性),使得原本由于接口不兼容而不能一起工作的那些类(对象)可以正常协作。简单理解就是为兼容而生的 “转换器”</p><h1 id="例子:"><a href="#例子:" class="headerlink" title="例子:"></a>例子:</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Adapter</span> {</span><br><span class="line"><span class="title function_">specificRequest</span>(<span class="params"></span>) {</span><br><span class="line"><span class="keyword">return</span> <span class="string">'德国标准插头'</span></span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Target</span> {</span><br><span class="line"><span class="title function_">constructor</span>(<span class="params"></span>) {</span><br><span class="line"><span class="variable language_">this</span>.<span class="property">adapter</span> = <span class="keyword">new</span> <span class="title class_">Adapter</span>()</span><br><span class="line">}</span><br><span class="line"><span class="title function_">request</span>(<span class="params"></span>) {</span><br><span class="line"><span class="keyword">let</span> info = <span class="string">`<span class="subst">${<span class="variable language_">this</span>.adapter.specificRequest()}</span>---转换成---中国插头`</span></span><br><span class="line"><span class="keyword">return</span> info</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">let</span> target = <span class="keyword">new</span> <span class="title class_">Target</span>()</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">info</span>(target.<span class="title function_">request</span>())</span><br><span class="line"></span><br><span class="line"><span class="comment">// $('selector').on 的实现</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">on</span>(<span class="params">target, event, callback</span>) {</span><br><span class="line"> <span class="keyword">if</span> (target.<span class="property">addEventListener</span>) {</span><br><span class="line"> <span class="comment">// 标准事件监听</span></span><br><span class="line"> target.<span class="title function_">addEventListener</span>(event, callback);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (target.<span class="property">attachEvent</span>) {</span><br><span class="line"> <span class="comment">// IE低版本事件监听</span></span><br><span class="line"> target.<span class="title function_">attachEvent</span>(event, callback)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 低版本浏览器事件监听</span></span><br><span class="line"> target[<span class="string">`on<span class="subst">${event}</span>`</span>] = callback</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>js设计模式-建造者模式</title>
<link href="/posts/90039cb8.html"/>
<url>/posts/90039cb8.html</url>
<content type="html"><![CDATA[<h1 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h1><p>  将一个复杂对象的构建层与其表示层分离,同样的构建过程可以采用不同的并表示</p><h1 id="与工厂模式的区别"><a href="#与工厂模式的区别" class="headerlink" title="与工厂模式的区别"></a>与工厂模式的区别</h1><p>  工厂模式主要是为了创建对象实例或者类簇(抽象工厂),关心的是最终产出(创建)的是什么,而不关心创建的过程。<br>  而建造者模式关心的是创建这个对象的整个过程,甚至于创建对象的每一个细节。 以下以创建应聘者为例:应聘者有兴趣爱好,姓名和期望的职位等等</p><h1 id="解决的问题"><a href="#解决的问题" class="headerlink" title="解决的问题"></a>解决的问题</h1><p>  方便用户创建复杂的对象(不需要知道实现过程)<br>  代码复用性 & 封装性(将对象构建过程和细节进行封装 & 复用)</p><h1 id="例子:"><a href="#例子:" class="headerlink" title="例子:"></a>例子:</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建一个人</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">PersonBuilder</span>(<span class="params">params</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">skill</span> = (params && params.<span class="property">skill</span>) || <span class="string">"保密"</span>;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">hbody</span> = (params && params.<span class="property">hbody</span>) || <span class="string">"保密"</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 人的原型方法</span></span><br><span class="line"> <span class="title class_">PersonBuilder</span>.<span class="property"><span class="keyword">prototype</span></span> = {</span><br><span class="line"> <span class="attr">getSkill</span>: <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">skill</span>);</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">getHbody</span>: <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">hbody</span>);</span><br><span class="line"> },</span><br><span class="line"> };</span><br><span class="line"> <span class="comment">//实例化姓名类</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Named</span>(<span class="params">name</span>) {</span><br><span class="line"> <span class="keyword">var</span> that = <span class="variable language_">this</span>;</span><br><span class="line"> (<span class="keyword">function</span> (<span class="params">name, that</span>) {</span><br><span class="line"> that.<span class="property">wholeName</span> = name;</span><br><span class="line"> <span class="keyword">if</span> (name.<span class="title function_">indexOf</span>(<span class="string">" "</span>) > -<span class="number">1</span>) {</span><br><span class="line"> that.<span class="property">firstName</span> = name.<span class="title function_">slice</span>(<span class="number">0</span>, name.<span class="title function_">indexOf</span>(<span class="string">" "</span>));</span><br><span class="line"> that.<span class="property">secondName</span> = name.<span class="title function_">slice</span>(name.<span class="title function_">indexOf</span>(<span class="string">" "</span>));</span><br><span class="line"> }</span><br><span class="line"> })(name, that);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//实例化职位类</span></span><br><span class="line"> <span class="keyword">var</span> <span class="title class_">Work</span> = <span class="keyword">function</span> (<span class="params">work</span>) {</span><br><span class="line"> <span class="keyword">var</span> that = <span class="variable language_">this</span>;</span><br><span class="line"> <span class="comment">//构造器</span></span><br><span class="line"> <span class="comment">//构造函数中通过传入的职位特征来设置相应职位以及描述</span></span><br><span class="line"> (<span class="keyword">function</span> (<span class="params">work, that</span>) {</span><br><span class="line"> <span class="keyword">switch</span> (work) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"code"</span>:</span><br><span class="line"> that.<span class="property">work</span> = <span class="string">"工程师"</span>;</span><br><span class="line"> that.<span class="property">workDescript</span> = <span class="string">"每天沉醉于编程"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"UI"</span>:</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"UE"</span>:</span><br><span class="line"> that.<span class="property">work</span> = <span class="string">"设计师"</span>;</span><br><span class="line"> that.<span class="property">workDescript</span> = <span class="string">"设计更似一种艺术"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">"teach"</span>:</span><br><span class="line"> that.<span class="property">work</span> = <span class="string">"教师"</span>;</span><br><span class="line"> that.<span class="property">workDescript</span> = <span class="string">"分享也是一种快乐"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="attr">default</span>:</span><br><span class="line"> that.<span class="property">work</span> = work;</span><br><span class="line"> that.<span class="property">workDescript</span> = <span class="string">"对不起,我们还不清楚您所选择职位的相关描述"</span>;</span><br><span class="line"> }</span><br><span class="line"> })(work, that);</span><br><span class="line"> };</span><br><span class="line"> <span class="comment">//更换期望的职位</span></span><br><span class="line"> <span class="title class_">Work</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">changeWork</span> = <span class="keyword">function</span> (<span class="params">work</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">work</span> = work;</span><br><span class="line"> };</span><br><span class="line"> <span class="comment">//添加对职位的描述</span></span><br><span class="line"> <span class="title class_">Work</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">changeDescript</span> = <span class="keyword">function</span> (<span class="params">sentence</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">workDescript</span> = sentence;</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params">name, work</span>) {</span><br><span class="line"> <span class="keyword">var</span> _person = <span class="keyword">new</span> <span class="title class_">PersonBuilder</span>();</span><br><span class="line"> </span><br><span class="line"> _person.<span class="property">name</span> = <span class="keyword">new</span> <span class="title class_">Named</span>(name);</span><br><span class="line"> _person.<span class="property">work</span> = <span class="keyword">new</span> <span class="title class_">Work</span>(work);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> _person;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">var</span> person = <span class="keyword">new</span> <span class="title class_">Person</span>(<span class="string">"xiao ming"</span>, <span class="string">"code"</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(person);</span><br><span class="line"> person.<span class="property">work</span>.<span class="title function_">changeDescript</span>(<span class="string">"更改描述!"</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(person.<span class="property">work</span>.<span class="property">workDescript</span>); <span class="comment">//更改描述!</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>js设计模式-工厂模式</title>
<link href="/posts/2d900bbb.html"/>
<url>/posts/2d900bbb.html</url>
<content type="html"><![CDATA[<h1 id="什么是工厂模式:"><a href="#什么是工厂模式:" class="headerlink" title="什么是工厂模式:"></a>什么是工厂模式:</h1><p>  工厂模式其实就是封装对象的创建过程,使得创建对象的逻辑与使用对象的逻辑分离开来。</p><h2 id="简单工程模式"><a href="#简单工程模式" class="headerlink" title="简单工程模式"></a>简单工程模式</h2><p>  简单工厂模式又叫静态工厂模式,由一个工厂对象决定创建某一种产品对象类的实例。主要用来创建同一类对象。</p><h1 id="例子:"><a href="#例子:" class="headerlink" title="例子:"></a>例子:</h1><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"> <span class="comment">//User类</span></span><br><span class="line"> <span class="keyword">class</span> <span class="title class_">User</span> {</span><br><span class="line"> <span class="comment">//构造器</span></span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params">opt</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">name</span> = opt.<span class="property">name</span>;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">viewPage</span> = opt.<span class="property">viewPage</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//静态方法</span></span><br><span class="line"> <span class="keyword">static</span> <span class="title function_">getInstance</span>(<span class="params">role</span>) {</span><br><span class="line"> <span class="keyword">switch</span> (role) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'superAdmin'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">User</span>({ <span class="attr">name</span>: <span class="string">'超级管理员'</span>, <span class="attr">viewPage</span>: [<span class="string">'首页'</span>, <span class="string">'通讯录'</span>, <span class="string">'发现页'</span>, <span class="string">'应用数据'</span>, <span class="string">'权限管理'</span>] });</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'admin'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">User</span>({ <span class="attr">name</span>: <span class="string">'管理员'</span>, <span class="attr">viewPage</span>: [<span class="string">'首页'</span>, <span class="string">'通讯录'</span>, <span class="string">'发现页'</span>, <span class="string">'应用数据'</span>] });</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'user'</span>:</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">User</span>({ <span class="attr">name</span>: <span class="string">'普通用户'</span>, <span class="attr">viewPage</span>: [<span class="string">'首页'</span>, <span class="string">'通讯录'</span>, <span class="string">'发现页'</span>] });</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="attr">default</span>:</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">'参数错误, 可选参数:superAdmin、admin、user'</span>)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用</span></span><br><span class="line"><span class="keyword">let</span> superAdmin = <span class="title class_">User</span>.<span class="title function_">getInstance</span>(<span class="string">'superAdmin'</span>);</span><br><span class="line"><span class="keyword">let</span> admin = <span class="title class_">User</span>.<span class="title function_">getInstance</span>(<span class="string">'admin'</span>);</span><br><span class="line"><span class="keyword">let</span> normalUser = <span class="title class_">User</span>.<span class="title function_">getInstance</span>(<span class="string">'user'</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(superAdmin)</span><br></pre></td></tr></table></figure><h2 id="工厂方法模式"><a href="#工厂方法模式" class="headerlink" title="工厂方法模式"></a>工厂方法模式</h2><p>  将实际创建对象工作推迟到子类当中,核心类就成了抽象类。这样添加新的类时就无需修改工厂方法,只需要将子类注册进工厂方法的原型对象中即可。;</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">FunctionFactory</span>(<span class="params">role</span>) {</span><br><span class="line"> <span class="keyword">if</span>(!([<span class="string">'admin'</span>, <span class="string">'developer'</span>].<span class="title function_">indexOf</span>(role) > -<span class="number">1</span>)){</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'参数只能为 admin 或 developer'</span>);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 安全的工厂方法</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">this</span> <span class="keyword">instanceof</span> <span class="title class_">FunctionFactory</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>[role]();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">FunctionFactory</span>(role);</span><br><span class="line">}</span><br><span class="line"><span class="title class_">FunctionFactory</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">show</span> = <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">var</span> str = <span class="string">'是一个'</span> + <span class="variable language_">this</span>.<span class="property">role</span> + <span class="string">', 权限:'</span> + <span class="variable language_">this</span>.<span class="property">permissions</span>.<span class="title function_">join</span>(<span class="string">', '</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(str)</span><br><span class="line">}</span><br><span class="line"><span class="title class_">FunctionFactory</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">admin</span> = <span class="keyword">function</span> (<span class="params">permissions</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">role</span> = <span class="string">'管理员'</span>;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">permissions</span> = [<span class="string">'设置'</span>, <span class="string">'删除'</span>, <span class="string">'新增'</span>, <span class="string">'创建'</span>, <span class="string">'开发'</span>, <span class="string">'推送'</span>, <span class="string">'提问'</span>, <span class="string">'评论'</span>];</span><br><span class="line">}</span><br><span class="line"><span class="title class_">FunctionFactory</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">developer</span> = <span class="keyword">function</span> (<span class="params">permissions</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">role</span> = <span class="string">'开发者'</span>;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">permissions</span> = [<span class="string">'开发'</span>, <span class="string">'推送'</span>, <span class="string">'提问'</span>, <span class="string">'评论'</span>];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> xm = <span class="title class_">FunctionFactory</span>(<span class="string">'admin'</span>);</span><br><span class="line">xm.<span class="title function_">show</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> xh = <span class="keyword">new</span> <span class="title class_">FunctionFactory</span>(<span class="string">'developer'</span>);</span><br><span class="line">xh.<span class="title function_">show</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> xl = <span class="keyword">new</span> <span class="title class_">FunctionFactory</span>(<span class="string">'guest'</span>);</span><br><span class="line">xl.<span class="title function_">show</span>();</span><br></pre></td></tr></table></figure><h3 id="安全工厂模式玩法的好处"><a href="#安全工厂模式玩法的好处" class="headerlink" title="安全工厂模式玩法的好处"></a>安全工厂模式玩法的好处</h3><p>  1.避免使用new关键字。在JavaScript中,使用new关键字创建对象可能会带来一些安全问题,例如可能会被恶意代码利用创建一个用于攻击的对象。安全工厂方法避免了使用new,从而减少了这种风险。<br>  2.可以实现封装和隐藏实现。安全工厂方法可以将关键的创建对象的代码封装在内部,从而隐藏实现细节,提高代码的安全性和可维护性。<br>  3.更易于维护。由于安全工厂方法可以提供统一的访问接口,因此更容易进行代码的维护和升级。<br>  4.可以提高代码的可测试性。由于安全工厂方法可以实现封装和隐藏实现,因此可以更轻松地进行单元测试和集成测试,从而提高代码的质量和可测试性。。</p><!-- ## 抽象工厂模式抽象工厂 只留对外的口子,不做事,留给外界覆盖(子类重写接口方法以便创建的时候指定自己的对象类型)。主要用于对产品类簇的创建,不直接生成实例(简单工厂模式和工厂方法模式都是生成实例)。// 抽象类是一种声明但不能使用的类,子类必须先实现其方法才能调用;// 可以在抽象类中定义一套规范,供子类去继承实现;// 1、优点,通过工厂模式,我们可以快速创建大量相似对象,没有重复代码。// 2、缺点,工厂模式创建的对象属于Object,无法区分对象类型,这也是工厂模式没有广泛使用的原因。// 可以通过构造函数来知道 -->]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>js设计模式-单例模式</title>
<link href="/posts/888898f6.html"/>
<url>/posts/888898f6.html</url>
<content type="html"><![CDATA[<h1 id="什么是单例模式"><a href="#什么是单例模式" class="headerlink" title="什么是单例模式"></a>什么是单例模式</h1><p>  单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。<br>  这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。<br>  注意:<br>  1、单例类只能有一个实例。<br>  2、单例类必须自己创建自己的唯一实例。<br>  3、单例类必须给所有其他对象提供这一实例。</p><h1 id="如何实现"><a href="#如何实现" class="headerlink" title="如何实现"></a>如何实现</h1><p>  肯定是有一个变量将第一次new生成的实例对象保存了下来,后面再执行new的时候,就直接返回第一次生成的实例对象,这样就实现了单例。</p><h1 id="主要优点:"><a href="#主要优点:" class="headerlink" title="主要优点:"></a>主要优点:</h1><p>  1、提供了对唯一实例的受控访问。<br>  2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。<br>  3、允许可变数目的实例。</p><h1 id="主要缺点:"><a href="#主要缺点:" class="headerlink" title="主要缺点:"></a>主要缺点:</h1><p>  1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。<br>  2、单例类的职责过重,在一定程度上违背了“单一职责原则”。<br>  3、滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。</p><h1 id="适用场景"><a href="#适用场景" class="headerlink" title="适用场景"></a>适用场景</h1><p>  在以下情况下可以考虑使用单例模式:</p><ul><li>(1) 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。</li><li>(2) 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。</li></ul><h1 id="例子:"><a href="#例子:" class="headerlink" title="例子:"></a>例子:</h1> <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">let</span> <span class="title class_">CreateSingleton</span> = (<span class="keyword">function</span>(<span class="params"></span>){</span><br><span class="line"> <span class="keyword">let</span> instance;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">function</span>(<span class="params">name</span>) {</span><br><span class="line"> <span class="keyword">if</span> (instance) {</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line"> <span class="keyword">return</span> instance = <span class="variable language_">this</span>;</span><br><span class="line"> }</span><br><span class="line">})();</span><br><span class="line"><span class="title class_">CreateSingleton</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">getName</span> = <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="title class_">Winner</span> = <span class="keyword">new</span> <span class="title class_">CreateSingleton</span>(<span class="string">'Winner'</span>);</span><br><span class="line"><span class="keyword">let</span> <span class="title class_">Looser</span> = <span class="keyword">new</span> <span class="title class_">CreateSingleton</span>(<span class="string">'Looser'</span>);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Winner</span> === <span class="title class_">Looser</span>); <span class="comment">// true</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Winner</span>.<span class="title function_">getName</span>()); <span class="comment">// 'Winner'</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Looser</span>.<span class="title function_">getName</span>()); <span class="comment">// 'Winner'</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Winner</span>) <span class="comment">// 'Winner'</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Looser</span>)</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 设计模式 </category>
</categories>
<tags>
<tag> JavaScript </tag>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>Webpack基础教程</title>
<link href="/posts/4db0c680.html"/>
<url>/posts/4db0c680.html</url>
<content type="html"><![CDATA[<h1 id="什么是Webpack"><a href="#什么是Webpack" class="headerlink" title="什么是Webpack"></a>什么是Webpack</h1><p>  webpack是一个打包工具,他的宗旨是一切静态资源皆可打包。有人就会问为什么要webpack?webpack是现代前端技术的基石,常规的开发方式,比如jquery,html,css静态网页开发已经落后了。现在是MVVM的时代,数据驱动界面。webpack它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。</p><h2 id="Webpack-五个核心"><a href="#Webpack-五个核心" class="headerlink" title="Webpack 五个核心"></a>Webpack 五个核心</h2><pre><code>1.Entry 入口(Entry)指示Webpack以哪个文件为入口起点开始打包,分析构建内部依赖图。2.Output 输出(Output)指示Webpack打包后的资源bundles输出到哪里去,以及如何命名。3.Loader Loader让Webpack能够去处理那些非JavaScript文件(webpack自身只理解Javascript)4.Plugins 插件(plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩, 一直到重新定义环境中的变量等。5.Mode 模式(mode)指示Webpack使用相应模式的配置 选项: 1)development 能让代码本地调试运行的环境 2)production 能让代码优化上线运行的环境</code></pre><h2 id="图片压缩"><a href="#图片压缩" class="headerlink" title="图片压缩"></a>图片压缩</h2><pre><code>小于8kb 压缩成base64 变成字符串 优势:不需要额外发请求 减少请求资源 降低服务器压力 劣势:体积变大 <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">test</span>: <span class="regexp">/\.(png|jpe?g|gif|webp|svg)$/</span>,</span><br><span class="line"> <span class="attr">type</span>: <span class="string">'asset'</span>, <span class="comment">//会转化成base64</span></span><br><span class="line"> <span class="attr">parser</span>: {</span><br><span class="line"> <span class="attr">dataUrlCondition</span>: {</span><br><span class="line"> <span class="attr">maxSize</span>: <span class="number">8</span> * <span class="number">1024</span>, <span class="comment">//8kb</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">generator</span>: {</span><br><span class="line"> <span class="comment">// 输出图片名称</span></span><br><span class="line"> <span class="comment">// [hash:10] 表示只取 前十位</span></span><br><span class="line"> <span class="attr">filename</span>: <span class="string">'static/img/[hash:10][ext][query]'</span></span><br><span class="line"> }</span><br><span class="line">},</span><br></pre></td></tr></table></figure></code></pre><h2 id="处理js-资源"><a href="#处理js-资源" class="headerlink" title="处理js 资源"></a>处理js 资源</h2><pre><code>有人可能会问,js 资源 Webpack 不能已经处理了吗,为什么我们还要处理呢? 原因是 Webpack 对s 处理是有限的,只能编译s 中 ES 模块化语法,不能编译其他语法,导致s 不能在E 等浏览器运行,所以我们希望做一些兼容性处理。 其次开发中,团队对代码格式是有严格要求的,我们不能由肉眼去检测代码格式,需要使用专业的工具来检测。。针对is兼容性处理,我们便用 Babel 来完成。针对代码格式,我们使用 Eslint 来完成我们先完成 Eslint,检测代码格式无误后,在由 Babel 做代码兼容性处理</code></pre><h2 id="Eslint"><a href="#Eslint" class="headerlink" title="Eslint"></a>Eslint</h2><pre><code>可组装的 JavaScript 和JSX 检查工具这句话意思就是:它是用来检测 is 和sx 语法的工具。可以配置各项功能我们使用 Eslint,关键是写 Eslint 配置文件,里面写上各种 rules 规则,将来运行 Eslint 时就会以写的规则对代码进行检查</code></pre><h2 id="babel"><a href="#babel" class="headerlink" title="babel"></a>babel</h2><pre><code>JavaScript 编译器。主要用于将 ES6 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境 </code></pre><h2 id="开发服务器-amp-自动化"><a href="#开发服务器-amp-自动化" class="headerlink" title="开发服务器&自动化"></a>开发服务器&自动化</h2><pre><code>每次写完代码都需要手动输入指令才能编译代码,太麻烦了,我们希望一切自动化第一步: 下载包 npm i webpack-dev-server -D第二步: 配置 <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 开发服务器: : 不会输出资源 不会去进行打包 在内存中打包 </span></span><br><span class="line"><span class="attr">devServer</span>: {</span><br><span class="line"> <span class="attr">host</span>: <span class="string">"localhost"</span>, <span class="comment">// 启动服务器域名</span></span><br><span class="line"> <span class="attr">port</span>: <span class="string">"3000"</span>, <span class="comment">// 启动服务器端口号</span></span><br><span class="line"> <span class="attr">open</span>: <span class="literal">true</span>, <span class="comment">// 是否自动打开浏览器</span></span><br><span class="line">},</span><br></pre></td></tr></table></figure></code></pre><h2 id="生产模式"><a href="#生产模式" class="headerlink" title="生产模式"></a>生产模式</h2><pre><code>生产模式是开发完成代码后,我们需要得到代码将来部署上线。这个模式下我们主要对代码进行优化,让其运行性能更好。优化主要从两个角度出发:1.优化代码运行性能2.优化代码打包速度</code></pre><h2 id="Css-处理"><a href="#Css-处理" class="headerlink" title="Css 处理"></a>Css 处理</h2><pre><code>#提取 Css 成单独文件Css 文件目前被打包到 js 文件中,当 js 文件加载时,会创建一个 style 标签来生成样式这样对于网站来说,会出现闪屏现象,用户体验不好我们应该是单独的 Css 文件,通过 link 标签加载性能才好npm i mini-css-extract-plugin -D</code></pre><h2 id="Css-兼容性处理"><a href="#Css-兼容性处理" class="headerlink" title="Css 兼容性处理"></a>Css 兼容性处理</h2><pre><code>1. 下载包npm i postcss-loader postcss postcss-preset-env -Dcss-loder 下面<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">loader</span>: <span class="string">"postcss-loader"</span>,</span><br><span class="line"> <span class="attr">options</span>: {</span><br><span class="line"> <span class="attr">postcssOptions</span>: {</span><br><span class="line"> <span class="attr">plugins</span>: [</span><br><span class="line"> <span class="string">"postcss-preset-env"</span>, <span class="comment">// 能解决大多数样式兼容性问题</span></span><br><span class="line"> ],</span><br><span class="line"> },</span><br><span class="line"> },</span><br><span class="line">},</span><br></pre></td></tr></table></figure>再去package.json 取配置 兼容到什么程度</code></pre><h1 id="开发模式参考:-生产模式稍加修改就可以"><a href="#开发模式参考:-生产模式稍加修改就可以" class="headerlink" title="开发模式参考:(生产模式稍加修改就可以)"></a>开发模式参考:(生产模式稍加修改就可以)</h1><pre><code><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> webpack.config.js webpack的配置文件</span></span><br><span class="line"><span class="comment"> 作用:指示webpack干哪些活(当你运行webpack指令时,会加载里面的配置)</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"> 所有构建工具都是基于nodejs平台运行~ 模块化默认采用commonjs</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// resoleve用来拼接绝对路径的方法</span></span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">ESLintPlugin</span> = <span class="built_in">require</span>(<span class="string">'eslint-webpack-plugin'</span>);</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">HtmlWebpackPlugin</span> = <span class="built_in">require</span>(<span class="string">'html-webpack-plugin'</span>);</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">MiniCssExtractPlugin</span> = <span class="built_in">require</span>(<span class="string">'mini-css-extract-plugin'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 用来获取样式的loader</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getStyle</span>(<span class="params">pre</span>) {</span><br><span class="line"> <span class="keyword">return</span>[</span><br><span class="line"> <span class="comment">// 'style-loader', // 将js种css通过创建style标签 添加到html文件中生效</span></span><br><span class="line"> <span class="title class_">MiniCssExtractPlugin</span>.<span class="property">loader</span>, <span class="comment">// 提取css成单独的文件</span></span><br><span class="line"> <span class="string">'css-loader'</span>, <span class="comment">//将css编译成commonjs模块到js种</span></span><br><span class="line"> {</span><br><span class="line"> <span class="attr">loader</span>: <span class="string">"postcss-loader"</span>,</span><br><span class="line"> <span class="attr">options</span>: {</span><br><span class="line"> <span class="attr">postcssOptions</span>: {</span><br><span class="line"> <span class="attr">plugins</span>: [</span><br><span class="line"> <span class="string">"postcss-preset-env"</span>, <span class="comment">// 能解决大多数样式兼容性问题</span></span><br><span class="line"> ],</span><br><span class="line"> },</span><br><span class="line"> },</span><br><span class="line"> },</span><br><span class="line"> pre,</span><br><span class="line"> ].<span class="title function_">filter</span>(<span class="title class_">Boolean</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = {</span><br><span class="line"> <span class="comment">// 写webpack配置</span></span><br><span class="line"> <span class="comment">// 入口起点</span></span><br><span class="line"> <span class="attr">entry</span>: <span class="string">'./src/main.js'</span>,</span><br><span class="line"> <span class="comment">// 输出</span></span><br><span class="line"> <span class="attr">output</span>: {</span><br><span class="line"> <span class="comment">// 所有文件的输出路径</span></span><br><span class="line"> <span class="comment">// 入口文件打包输出文件名</span></span><br><span class="line"> <span class="attr">filename</span>: <span class="string">'static/js/dist.js'</span>,</span><br><span class="line"> <span class="comment">// 输出路径</span></span><br><span class="line"> <span class="comment">// _dirname nodejs的变量,代表当前文件的目录绝对路径</span></span><br><span class="line"> <span class="comment">// path: path.resolve(__dirname, '../dist'),</span></span><br><span class="line"> <span class="comment">// 开发模式 无需输出</span></span><br><span class="line"> <span class="attr">path</span>: <span class="literal">undefined</span>, </span><br><span class="line"> <span class="comment">// 自动清空上次打包</span></span><br><span class="line"> <span class="comment">// 原理:将path整个目录清空 再打包</span></span><br><span class="line"> <span class="attr">clean</span>: <span class="literal">true</span></span><br><span class="line"> },</span><br><span class="line"> <span class="comment">// 加载器</span></span><br><span class="line"> <span class="attr">module</span>: {</span><br><span class="line"> <span class="comment">// loader的配置</span></span><br><span class="line"> <span class="attr">rules</span>:[</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// 每个文件只能被其中的一个loader配置处理</span></span><br><span class="line"> <span class="attr">oneOf</span>:[</span><br><span class="line"> { <span class="attr">test</span>: <span class="regexp">/\.css$/</span>, <span class="comment">//只检测 css</span></span><br><span class="line"> <span class="attr">use</span>: <span class="title function_">getStyle</span>()</span><br><span class="line"> }, <span class="comment">// 执行顺序 从右到左 从下到上</span></span><br><span class="line"> {</span><br><span class="line"> <span class="attr">test</span>: <span class="regexp">/\.less$/</span>,</span><br><span class="line"> <span class="attr">use</span>: <span class="title function_">getStyle</span>(<span class="string">'less-loader'</span>)</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">test</span>: <span class="regexp">/\.(png|jpe?g|gif|webp|svg)$/</span>,</span><br><span class="line"> <span class="attr">type</span>: <span class="string">'asset'</span>, <span class="comment">//会转化成base64</span></span><br><span class="line"> <span class="attr">parser</span>: {</span><br><span class="line"> <span class="attr">dataUrlCondition</span>: {</span><br><span class="line"> <span class="attr">maxSize</span>: <span class="number">8</span> * <span class="number">1024</span>, <span class="comment">//8kb</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> <span class="attr">generator</span>: {</span><br><span class="line"> <span class="comment">// 输出图片名称</span></span><br><span class="line"> <span class="comment">// [hash:10] 表示只取 前十位</span></span><br><span class="line"> <span class="attr">filename</span>: <span class="string">'static/img/[hash:10][ext][query]'</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">test</span>: <span class="regexp">/\.(ttf|woff2?|mp3|mp4|avi)$/</span>,</span><br><span class="line"> <span class="attr">type</span>: <span class="string">'asset/resource'</span>, <span class="comment">//不会转化成base64</span></span><br><span class="line"> <span class="attr">generator</span>: {</span><br><span class="line"> <span class="comment">// 输出图片名称</span></span><br><span class="line"> <span class="comment">// [hash:10] 表示只取 前十位</span></span><br><span class="line"> <span class="attr">filename</span>: <span class="string">'static/media/[hash:10][ext][query]'</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> <span class="attr">test</span>: <span class="regexp">/\.js$/</span>,</span><br><span class="line"> <span class="comment">// exclude: /(node_modules|bower_components)/, //排除文件</span></span><br><span class="line"> <span class="comment">// exclude: /node_modules/, // 排除node_modules代码不编译</span></span><br><span class="line"> <span class="attr">include</span>: path.<span class="title function_">resolve</span>(__dirname, <span class="string">"../src"</span>), <span class="comment">// 也可以用包含</span></span><br><span class="line"> <span class="attr">use</span>: {</span><br><span class="line"> <span class="attr">loader</span>: <span class="string">'babel-loader'</span>,</span><br><span class="line"> <span class="comment">// options: {</span></span><br><span class="line"> <span class="comment">// presets: ['@babel/preset-env']</span></span><br><span class="line"> <span class="comment">// }</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 详细的loader配置</span></span><br><span class="line"> <span class="comment">// {</span></span><br><span class="line"> <span class="comment">// // 匹配哪些文件</span></span><br><span class="line"> <span class="comment">// test: /\.css$/,</span></span><br><span class="line"> <span class="comment">// // 使用哪些loader进行处理</span></span><br><span class="line"> <span class="comment">// use: [</span></span><br><span class="line"> <span class="comment">// // use数组中执行顺序:从右到左,从下到上,依次执行</span></span><br><span class="line"> <span class="comment">// // 创建style标签,将js中的样式资源插入进行,添加到head中生效</span></span><br><span class="line"> <span class="comment">// // 'style-loader',</span></span><br><span class="line"> <span class="comment">// // 将css文件变成conmonjs模块加载js中,里面内容时样式字符串</span></span><br><span class="line"> <span class="comment">// // 'css-loader',</span></span><br><span class="line"> <span class="comment">// 'style-loader',</span></span><br><span class="line"> <span class="comment">// 'css-loader'</span></span><br><span class="line"> <span class="comment">// ]</span></span><br><span class="line"> <span class="comment">// }</span></span><br><span class="line"> ],</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">// plugins的配置</span></span><br><span class="line"> <span class="attr">plugins</span>:[</span><br><span class="line"> <span class="comment">// 详细的plugins的配置</span></span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">ESLintPlugin</span>({</span><br><span class="line"> <span class="comment">// 检测哪些文件</span></span><br><span class="line"> <span class="attr">context</span>: path.<span class="title function_">resolve</span>(__dirname, <span class="string">'../src'</span>),</span><br><span class="line"> <span class="attr">exclude</span>: <span class="string">"node_modules"</span>, <span class="comment">// 默认值</span></span><br><span class="line"> }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">HtmlWebpackPlugin</span>({</span><br><span class="line"> <span class="comment">// 以 public/index.html 为模板创建文件</span></span><br><span class="line"> <span class="comment">// 新的html文件有两个特点:1. 内容和源文件一致 2. 自动引入打包生成的js等资源</span></span><br><span class="line"> <span class="attr">template</span>: path.<span class="title function_">resolve</span>(__dirname, <span class="string">"../public/index.html"</span>),</span><br><span class="line"> }),</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">MiniCssExtractPlugin</span>({</span><br><span class="line"> <span class="attr">filename</span>: <span class="string">"static/css/main.css"</span></span><br><span class="line"> })</span><br><span class="line"> ],</span><br><span class="line"> <span class="comment">// 开发服务器: 不会输出资源 不会去进行打包 在内存中打包 </span></span><br><span class="line"> <span class="attr">devServer</span>: {</span><br><span class="line"> <span class="attr">host</span>: <span class="string">"localhost"</span>, <span class="comment">// 启动服务器域名</span></span><br><span class="line"> <span class="attr">port</span>: <span class="string">"3000"</span>, <span class="comment">// 启动服务器端口号</span></span><br><span class="line"> <span class="attr">open</span>: <span class="literal">true</span>, <span class="comment">// 是否自动打开浏览器</span></span><br><span class="line"> <span class="attr">hot</span>: <span class="literal">true</span>, <span class="comment">// 开启HMR功能(只能用于开发环境,生产环境不需要了)</span></span><br><span class="line"> },</span><br><span class="line"> <span class="comment">// 模式</span></span><br><span class="line"> <span class="attr">mode</span>: <span class="string">"development"</span>,</span><br><span class="line"> <span class="attr">devtool</span>: <span class="string">"cheap-module-source-map"</span>,</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 运行方式:</span></span><br><span class="line"><span class="comment">// npx webpack serve --config ./config/webpack.dev.js</span></span><br></pre></td></tr></table></figure></code></pre>]]></content>
<categories>
<category> 前端开发 </category>
</categories>
<tags>
<tag> Webpack基础 </tag>
</tags>
</entry>
</search>