-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
311 lines (167 loc) · 149 KB
/
atom.xml
File metadata and controls
311 lines (167 loc) · 149 KB
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>qinxs小站</title>
<subtitle>qinxs的个人博客</subtitle>
<link href="https://7bxing.com/atom.xml" rel="self"/>
<link href="https://7bxing.com/"/>
<updated>2022-02-26T11:43:21.000Z</updated>
<id>https://7bxing.com/</id>
<author>
<name>qinxs</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>Win32 API编程——前言</title>
<link href="https://7bxing.com/posts/67bdf631/"/>
<id>https://7bxing.com/posts/67bdf631/</id>
<published>2022-02-26T11:43:21.000Z</published>
<updated>2022-02-26T11:43:21.000Z</updated>
<content type="html"><![CDATA[<p>Windows 编程中使用的一些基本术语和编码约定</p><span id="more"></span><h2 id="什么是Win32-API?"><a href="#什么是Win32-API?" class="headerlink" title="什么是Win32 API?"></a>什么是Win32 API?</h2><p>简单来讲,就是微软为了保护操做系统的安全性和稳定性,不容许运行在用户层的进程随意操控系统内核,而是必须按照必定方式。咱们<strong>用户层要与系统内核层交互</strong>(好比对内存、进程操做),只能经过调用<strong>Windows内核层提供的接口函数,也就是Win32API</strong>来操控。这些API以DLL(动态连接库)的形式保存(在SYSTEM32文件夹中,你能够发现许多DLL文件),最经常使用的是<strong>kernel32.dll、user32.dll和gdi32.dll</strong>。</p><p>全部基于NT内核(XP到Win10都是基于NT内核开发)的Windows API均可以称为Win32,即使是64位系统,也用这个名称,由于64位系统是彻底兼容32位程序的(32位系统不能彻底兼容16位程序),因此你能够看到这些DLL名称都有个”32”的后缀。那咱们用C/C++写程序,没用到Win32,怎么也可以执行分配内存,打开进程等操做呢?实际上在Windows系统上的C/C++的运行库内部也是封装了Win32API。进一步说,<strong>全部运行在Windows用户层的程序必须得调用Win32API</strong>。</p><p>Windows采用分层结构,大体来讲就是(<strong>用户层->内核层->硬件抽象层->硬件层</strong>),每一层使用下一层提供的接口来与下一层进行交互。咱们平常使用的应用程序都是运行在用户层,经过调用内核层提供的接口(Win32API)来与内核层交互,而后系统会请求中断(调用nt*.dll函数),调用内核中的中断服务程序,进而对硬件抽象层进行操做,从而实现用户到硬件的交互。固然,也有许多程序是运行在内核层的(好比驱动程序),Windows没有公布用于内核层编程的源码,可是提供了WDK(Windows Driver Kit)来给程序员编写驱动程序,驱动程序可经过内核API,编写中断服务例程来操控硬件抽象层。</p><h2 id="为何要学Win32-API?"><a href="#为何要学Win32-API?" class="headerlink" title="为何要学Win32 API?"></a>为何要学Win32 API?</h2><p>如今用于windows平台的程序开发方式突飞猛进,种类繁多,好比使用Dephi、WPF、Qt等,开发效率远高于使用Win32 API开发,那为何还要学习使用Win32 API开发呢?</p><ol><li>理解Windows程序底层运行机制。</li><li>帮助学习Windows上其余的编程语言、平台。</li><li>实现其余库没有提供的高级功能,好比修改其余进程内存等。</li></ol><h2 id="开始前你必须知道"><a href="#开始前你必须知道" class="headerlink" title="开始前你必须知道"></a>开始前你必须知道</h2><p>语言基础: C/C++</p><p>开发平台: Visual Studio</p><p>编码格式:Unicode</p><h3 id="为何区分编码格式?"><a href="#为何区分编码格式?" class="headerlink" title="为何区分编码格式?"></a>为何区分编码格式?</h3><p>windows程序的编码格式分为两种:ANSI(MBCS:多字节字符集)和Unicode,Windows会按程序的编码格式解码字符。</p><p>ANSI:根据系统当前设置的语言采用不一样编码,好比系统语言设置为简体中文,则ANSI采用GBK编码。</p><p>Unicode:统一的字符集,在全部系统中均相同,每一个字符占用两个字节。</p><h3 id="为何使用Unicode?"><a href="#为何使用Unicode?" class="headerlink" title="为何使用Unicode?"></a>为何使用Unicode?</h3><ol><li>Windows NT是使用Unicode开发的,调用API时要把ANSI字符转换成Unicode字符,直接使用Unicode能够提升运行效率。</li><li>使你的程序在不一样语言的系统上运行时不会出现乱码。</li><li>一些API只能处理Unicode字符。</li></ol><h3 id="怎么设置Unicode?"><a href="#怎么设置Unicode?" class="headerlink" title="怎么设置Unicode?"></a>怎么设置Unicode?</h3><p>修改编译器设置</p><p> 项目->属性->高级->字符集:使用Unicode字符集</p><p>设置后观察</p><p> 项目->属性->C/C++->命令行:看到两个选项 /D “_UNICODE” /D “UNICODE”,说明已成功设置为Unicode编码,不然看到选项 /D “_MBCS”,说明使用的是MBCS编码。</p><p>其中_UNICODE定义在C运行库的头文件中,UNICODE定义在Windows的头文件中。</p><h2 id="尽可能使用Windows数据类型"><a href="#尽可能使用Windows数据类型" class="headerlink" title="尽可能使用Windows数据类型"></a>尽可能使用Windows数据类型</h2><p>在平时使用C/C++编程时,咱们都使用C/C++标准库提供的数据类型,好比char,short,int,long int等等,可是在使用Windows API编程时,咱们应该尽可能使用Windows提供的数据类型,由于Win32 API函数都是使用Windows数据类型编写的,因此你必需要认识它。事实上,这些Windows数据类型都是在windows头文件中对C/C++库原生类型的宏定义,本质上并没有差异。下面列举常见的Windows数据类型。</p><h3 id="类型前缀"><a href="#类型前缀" class="headerlink" title="类型前缀"></a>类型前缀</h3><p>c=const 常量</p><p>u=unsigned 无符号</p><p>p=pointer 指针</p><p>h=handle 句柄</p><p>w=word 字</p><p>dw=double word 双字</p><p>sz=strinszg terminated with a zero 以0结尾的字符串</p><p>lp=long pointer 长指针</p><h3 id="函数后缀"><a href="#函数后缀" class="headerlink" title="函数后缀"></a>函数后缀</h3><p>A=ansi字符 参数接受ANSI字符</p><p>W=wide宽字符 参数接受Unicode字符</p><p>EX=expand 扩展版函数,在原函数基础上增长某些新的特性</p><h3 id="Windows类型举例"><a href="#Windows类型举例" class="headerlink" title="Windows类型举例"></a>Windows类型举例</h3><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">typedef</span> <span class="type">int</span> INT;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">int</span> BOOL;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">int</span> UINT;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="type">unsigned</span> <span class="type">short</span> WORD;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> WORD near *PWORD;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> WORD far *LPWORD;</span><br></pre></td></tr></table></figure><blockquote><p>其余定义详见 <minwindef.h>near指针NP,far指针FP,long指针LP,是为了兼容16位程序,在32位编程中都为P(32位指针)</p></blockquote><h3 id="在字符串前添加-L标志"><a href="#在字符串前添加-L标志" class="headerlink" title="在字符串前添加 L标志"></a>在字符串前添加 L标志</h3><blockquote><p>该字符串将按宽字符(Unicode)编码</p></blockquote><p>TEXT、__TEXT(winnt.h内定义的宏)</p><p>若是 UNICODE被定义,则在字符串前添加L</p><p>_T、__T、_TEXT(tchar.h内定义的宏)</p><p>若是 _UNICODE被定义,则在字符串前添加L</p><figure class="highlight cpp"><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="meta">#<span class="keyword">ifdef</span> UNICODE</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __TEXT(x) L##x</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __TEXT(x) x</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><h3 id="带T前缀的数据类型"><a href="#带T前缀的数据类型" class="headerlink" title="带T前缀的数据类型"></a>带T前缀的数据类型</h3><blockquote><p>根据是否定义UNICODE选择使用宽/窄字符</p></blockquote><figure class="highlight cpp"><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="meta">#<span class="keyword">ifdef</span> UNICODE</span></span><br><span class="line"> <span class="keyword">typedef</span> <span class="type">wchar_t</span> TCHAR</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"> <span class="keyword">typedef</span> <span class="type">char</span> TCHAR</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>原文出处:<a href="https://www.cnblogs.com/celnghome/p/11999751.html">博客园 Celng</a><br>更多资料:<br><a href="https://cloud.tencent.com/developer/article/1057417">Win32平台数据类型总结</a><br><a href="https://docs.microsoft.com/zh-cn/windows/win32/learnwin32/windows-coding-conventions">Windows编码约定</a><br><a href="https://www.cnblogs.com/wingsummer/p/15250378.html">Win32基本知识总结</a></p>]]></content>
<summary type="html"><p>Windows 编程中使用的一些基本术语和编码约定</p></summary>
<category term="IT技术" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/"/>
<category term="Win32编程" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/Win32%E7%BC%96%E7%A8%8B/"/>
<category term="Win32术语及编码约定" scheme="https://7bxing.com/tags/Win32%E6%9C%AF%E8%AF%AD%E5%8F%8A%E7%BC%96%E7%A0%81%E7%BA%A6%E5%AE%9A/"/>
</entry>
<entry>
<title>【原创作品】Ease Bookmarks</title>
<link href="https://7bxing.com/posts/beb3fd2a/"/>
<id>https://7bxing.com/posts/beb3fd2a/</id>
<published>2021-12-27T13:01:23.000Z</published>
<updated>2021-12-27T13:01:23.000Z</updated>
<content type="html"><![CDATA[<p><strong>Ease-Bookmarks</strong>,是一款简单易用的书签管理器<br>为了替代浏览器原有书签栏而编写的扩展</p><span id="more"></span><p>在此基础上,尽可能满足各类 书签使用习惯 用户的需求</p><h2 id="主要功能"><a href="#主要功能" class="headerlink" title="主要功能"></a>主要功能</h2><p>修改书签的默认打开方式</p><p>对书签的各种基本操作(编辑、删除、移动等)</p><p>书签多列显示</p><p>快捷键支持</p><p>在未使用本扩展时,不占用后台</p><p>另外,本扩展对 <code>JS 小书签</code> 进行了特别支持~</p><blockquote><p>更新日志:<a href="https://github.com/qinxs/Ease-Bookmarks/blob/master/ChangeLog.md">ChangeLog.md</a></p></blockquote><h2 id="相关截图"><a href="#相关截图" class="headerlink" title="相关截图"></a>相关截图</h2><p><img src="https://gcore.jsdelivr.net/gh/qinxs/Ease-Bookmarks@master/screenshots/1-popup.png" alt="主窗口"></p><p><img src="https://gcore.jsdelivr.net/gh/qinxs/Ease-Bookmarks@master/screenshots/4-duolie.png" alt="多列布局"></p><p><img src="https://gcore.jsdelivr.net/gh/qinxs/Ease-Bookmarks@master/screenshots/5-options.png" alt="选项配置"></p><h2 id="使用快捷键"><a href="#使用快捷键" class="headerlink" title="使用快捷键"></a>使用快捷键</h2><h3 id="打开-x2F-关闭-本扩展"><a href="#打开-x2F-关闭-本扩展" class="headerlink" title="打开/关闭 本扩展"></a>打开/关闭 本扩展</h3><p>默认快捷键是 <code>Ctrl + Q</code>,你可以在如下管理页面进行修改:</p><ul><li>Chrome:<code>chrome://extensions/shortcuts</code></li><li>Edge:<code>edge://extensions/shortcuts</code><!-- - Firefox:`about:addons` -> 扩展 -> 设置图标 -> 管理扩展快捷键 --></li></ul><h3 id="功能键"><a href="#功能键" class="headerlink" title="功能键"></a>功能键</h3><ul><li>Ctrl:在 当前标签/新标签 打开页面</li><li>Shift:是否在后台打开页面</li></ul><h2 id="自定义"><a href="#自定义" class="headerlink" title="自定义"></a>自定义</h2><ul><li>别名(书签栏和其他书签,其他语言可能会需要)</li><li>自定义样式(popup 页面,DOM 结构可在 header 区域 <code>右键 -> 检查</code> 查看)</li></ul><h2 id="资源链接"><a href="#资源链接" class="headerlink" title="资源链接"></a>资源链接</h2><blockquote><p>如果觉得有用的话,可以在谷歌商店给个五星,GitHub 给个 Star,感谢~ </p></blockquote><p><a href="https://github.com/qinxs/Ease-Bookmarks"><img src="https://img.shields.io/badge/Source_Code-GitHub-blue" alt="Source Code"></a><br><a href="https://chrome.google.com/webstore/detail/ease-bookmarks/poefceffmekhjoadknillcbdifahongk"><img src="https://img.shields.io/chrome-web-store/v/poefceffmekhjoadknillcbdifahongk.svg" alt="Chrome Web Store"></a><br><a href="https://microsoftedge.microsoft.com/addons/detail/ease-bookmarks/addbgeibeffkokpabpbpmdpehfbegchl"><img src="https://img.shields.io/badge/dynamic/json?label=microsoft%20edge%20add-on&prefix=v&query=$.version&url=https://microsoftedge.microsoft.com/addons/getproductdetailsbycrxid/addbgeibeffkokpabpbpmdpehfbegchl" alt="Microsoft Edge Add-on"></a></p>]]></content>
<summary type="html"><p><strong>Ease-Bookmarks</strong>,是一款简单易用的书签管理器<br>为了替代浏览器原有书签栏而编写的扩展</p></summary>
<category term="原创作品" scheme="https://7bxing.com/categories/%E5%8E%9F%E5%88%9B%E4%BD%9C%E5%93%81/"/>
<category term="书签管理器" scheme="https://7bxing.com/tags/%E4%B9%A6%E7%AD%BE%E7%AE%A1%E7%90%86%E5%99%A8/"/>
</entry>
<entry>
<title>从AI导出Web的SVG的最佳设置</title>
<link href="https://7bxing.com/posts/f28f8693/"/>
<id>https://7bxing.com/posts/f28f8693/</id>
<published>2021-09-06T13:03:49.000Z</published>
<updated>2021-09-06T13:03:49.000Z</updated>
<content type="html"><![CDATA[<div class="note info"><p>偶尔需要自己动手画 SVG,但每次都忘记导出参数…<br>特此记录</p></div><span id="more"></span><h2 id="SVG-配置文件"><a href="#SVG-配置文件" class="headerlink" title="SVG 配置文件"></a>SVG 配置文件</h2><ul><li>SVG 1.0:所有现代台式机和移动浏览器都支持 SVG 1.1,因此请不要选择此选项。</li><li><strong>SVG 1.1:您几乎总是会想要这个。</strong></li><li>SVG Tiny / Basic:这是用于移动设备的 SVG 的子集。只有少数设备支持 SVG Tiny,而不支持完整规格,因此请使用 SVG 1.1。</li></ul><p>注意:SVG Tiny 不会减小文件大小,它只是 SVG 的一个子集,足以满足低处理能力的设备。它将丢弃渐变,不透明度,嵌入的字体和过滤器。ErikDahlström 说:所有 SVG 1.1 完整查看器都应该能够显示所有 SVG 1.1 Tiny / Basic 内容(根据规范),并且可能还会显示 Illustrator 产生的所有 SVG 1.2 Tiny 内容。</p><h2 id="字体"><a href="#字体" class="headerlink" title="字体"></a>字体</h2><p><strong>文字</strong></p><p>注意:如果图像中没有任何文本,则此设置无关紧要。</p><ul><li><p>Adobe CEF:切勿在打算在浏览器中显示它时使用此选项。据我所知,这是 Adobe 在 SVG 文件中嵌入字体的方式,仅 Adobe 的 SVG 查看器插件才支持。</p></li><li><p>SVG:这将字体嵌入为 SVG,Firefox 不支持,但是如果您打算仅支持移动设备(通常运行 webkit),则是一个不错的选择。</p></li><li><p><strong>创建轮廓:</strong>除非您有大量文本,否则您<strong>通常会希望执行此操作</strong>。如果您有大量文本,则需要在 WOFF 中嵌入字体,但是您必须手动执行此操作。</p></li></ul><p><strong>子集化</strong></p><ul><li><p>无:如果您不在乎用户计算机上的字体会退回到其他字体,则此选项将取消以前的设置并且不会嵌入任何字体。</p></li><li><p><strong>仅使用字形:大多数情况下,</strong>如果您选择嵌入字体,<strong>则需要使用此</strong>字形。它仅嵌入使用的字符,因此不会增加文件大小。</p></li><li><p>[其余子集]:这很清楚,您可以选择包含整个字体或它的子集。仅当 SVG 是动态的并且文本可能会根据用户输入而更改时,此选项才有用。</p></li></ul><h2 id="选项"><a href="#选项" class="headerlink" title="选项"></a>选项</h2><p><strong>图像位置</strong>:仅当您包含位图图片时才重要</p><ul><li><p><strong>嵌入:通常这就是您想要的</strong>,它会将图像编码为数据 uri,因此您只需上传一个文件,而不是带有其配套位图图像的 svg 文件。</p></li><li><p>链接:仅当您有多个引用一个位图文件的 svg 文件时才使用它(因此,每次渲染 svg 文件时都不会下载该文件)。</p></li></ul><p>请注意,如果通过 <code><img></code> 标记显示 SVG,则不会显示链接的位图图像,因为 <code>img</code> 不允许加载外部资源。此外:webkit 有一个错误,即使您将其嵌入,也不会在 svg 文件中显示位图图像。简而言之:<code><svg></code> 如果您打算嵌入或链接位图图像,请使用纯标签,请勿使用 <code><img></code>。</p><p><strong>保留 Illustrator 编辑功能</strong></p><p>我更喜欢将.ai 文件另存为我的源映像,并且将 SVG 文件视为 <code>Export for web</code> 功能。这样,您就可以专注于减小文件大小,并拥有具有所有编辑功能的矢量文件的原始副本。所以不要选择这个。</p><h2 id="高级选项"><a href="#高级选项" class="headerlink" title="高级选项"></a>高级选项</h2><p><strong>CSS 属性</strong></p><p>一般选择样式属性(偶尔选择样式元素)</p><p><strong>小数位数</strong></p><p><del>默认设置<code>3</code>为正常设置,您几乎可以忽略它。</del></p><p><strong>如果图像比较复杂,将该值设为 1(输出体积会大大减少),然后观察显示是否正常</strong></p><p>但是,如果您的路径真的很复杂,并且有很多点,请将此设置降低到 1 或什至 0 会大大减小文件大小。但是您必须小心,因为贝塞尔曲线段对此设置非常敏感,并且它们似乎有些变形。因此,如果降低此设置,请始终确保它在浏览器中看起来可以接受。</p><p><strong>编码方式</strong></p><p>字符编码背后的解释是相当技术性的,仅涉及带文本的 svg 文件。<strong>您最可能需要的编码是 UTF-8</strong>,除非您知道自己在做什么,否则不要更改它。</p><p><strong>针对 Adobe SVG Viewer 进行优化</strong></p><p>从浏览器本身不支持 SVG 开始,Adobe SVG Viewer 便是一个浏览器插件。我不知道它的作用,但这无关紧要,<strong>请不要检查</strong>。</p><p><strong>包括切片数据</strong></p><p>这会将元数据膨胀添加到您的 SVG 文件中,除非您打算稍后在 Illustrator 中打开 SVG 文件并找到您的切片(如果有),<strong>请不要选中此选项</strong></p><p><strong>包括 XMP</strong></p><p>有关文件的更多元数据,您可以 <a href="https://en.wikipedia.org/wiki/Extensible_Metadata_Platform">在 XMP 上阅读</a>。<strong>不要检查这个</strong></p><p><strong>输出更少的 <code><tspan></code> 元素</strong></p><p>如果您没有文字,则将显示为灰色。SVG 不支持字距调整表,因此,某些字符序列似乎间隔太远,即 <code>AVA</code>。Illustrator 通过添加 <code>tspan</code> 元素和微调字符位置来解决该问题。这增添了几分膨胀到文件<strong>,除非你更关心的不是文字的外观文件大小不查这个</strong>。</p><p><strong>在路径文字上使用 SVG <code><textPath></code> 元素</strong></p><p>如果您的路径上没有文字,则该字段将显示为灰色。在将文本放置在路径上时,浏览器的变化往往很大,因此 Illustrator 尝试通过对字符应用旋转和位置而不是将工作留给浏览器来提供帮助。<strong>除非您更关心文件的大小而不是文本的外观,否则请不要选中此选项</strong>。</p><h2 id="最终图"><a href="#最终图" class="headerlink" title="最终图"></a>最终图</h2><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/f28f8693/svg.png" alt=" 导出SVG " title="导出SVG"></p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><ul><li>生成的 SVG 可以能冗余 dom,查看源代码删除</li><li>SVG 图标 可以在浏览器开发者工具中 编辑 DOM</li><li><a href="https://zh.javascript.info/bezier-curve">贝塞尔曲线</a></li><li>AI 操作</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Ctrl + 左键 选择一部分(文字转换为轮廓后)</span><br><span class="line">Ctrl + 0 大小适应窗口</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><div class="note info"><p>偶尔需要自己动手画 SVG,但每次都忘记导出参数…<br>特此记录</p></div></summary>
<category term="未分类" scheme="https://7bxing.com/categories/%E6%9C%AA%E5%88%86%E7%B1%BB/"/>
<category term="Illustrator" scheme="https://7bxing.com/tags/Illustrator/"/>
</entry>
<entry>
<title>正则表达式</title>
<link href="https://7bxing.com/posts/2f57a694/"/>
<id>https://7bxing.com/posts/2f57a694/</id>
<published>2021-07-18T15:10:00.000Z</published>
<updated>2021-07-18T15:10:00.000Z</updated>
<content type="html"><![CDATA[<p>正则表达式(Regular Expression)是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。</p><span id="more"></span><p>给定一个正则表达式和另一个字符串,我们可以达到如下的目的:</p><ol><li>给定的字符串是否符合正则表达式的过滤逻辑(称作“匹配”);</li><li>可以通过正则表达式,从字符串中获取我们想要的特定部分。</li></ol><p>历史: <a href="http://zh.wiki.sxisa.org/wiki/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F#%E5%8E%86%E5%8F%B2">维基百科 - 正则表达式</a></p><h2 id="基础语法"><a href="#基础语法" class="headerlink" title="基础语法"></a>基础语法</h2><p><a href="https://deerchao.cn/tutorials/regex/regex.htm">正则表达式30分钟入门教程</a></p><p>菜鸟教程: <a href="https://www.runoob.com/regexp/regexp-syntax.html">正则表达式 - 语法</a></p><h2 id="优先权"><a href="#优先权" class="headerlink" title="优先权"></a>优先权</h2><table><thead><tr><th>优先权</th><th>运算符</th><th>描述</th></tr></thead><tbody><tr><td>最高</td><td>\</td><td>转义符</td></tr><tr><td>高</td><td>(), (?:), (?=), []</td><td>圆括号和方括号</td></tr><tr><td>中</td><td>*, +, ?, {n}, {n,}, {n,m}</td><td>限定符</td></tr><tr><td>低</td><td>^, $, \任何元字符、任何字符</td><td>定位点和序列(即:位置和顺序)</td></tr><tr><td>最低</td><td>|</td><td>替换,”或” 操作<br>字符具有高于替换运算符的优先级,<br>使得”m|food”匹配”m”或”food”。<br>若要匹配”mood”或”food”,<br>请使用括号创建子表达式,从而产生”(m|f)ood”。</td></tr></tbody></table><h2 id="正则性能优化"><a href="#正则性能优化" class="headerlink" title="正则性能优化"></a>正则性能优化</h2><p>正则是个很好用的利器,如果使用得当,如有神助,能省掉大量代码。当如果使用不当,则是处处埋坑。所以如何写一个高性能的正则表达式就尤为重要。</p><h3 id="避免量词嵌套"><a href="#避免量词嵌套" class="headerlink" title="避免量词嵌套"></a>避免量词嵌套</h3><p>举个简单的例子对比:</p><p>我们使用正则表达式 <code>/a*b/</code> 去匹配字符串 aaaaa</p><p>我们将以上正则修改成 <code>/(a*)*b/</code> 去匹配字符串 aaaaa</p><p>上两个正则的基本执行步骤可以简单认为是:</p><ol><li><p>贪婪匹配</p></li><li><p>回溯</p></li><li><p>直至发现匹配失败</p></li></ol><p>但令人惊奇的是,第一个正则的从开始匹配到匹配失败这个过程只有 14 步。而第二个正则却有 128 步之多。可想而知,嵌套量词会大大增加正则的执行过程。因为这其中进行了两层回溯,这个执行步骤增加的过程就如同算法复杂度从 O(n)上升到 O(n^2)的过程一般。</p><p>所以,面对量词嵌套,我们需作出适当的转化消除这些嵌套:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">(a*)* <=> (a+)* <=> (a*)+ <=> a* </span><br><span class="line">(a+)+ <=> a+ </span><br></pre></td></tr></table></figure><h3 id="使用非捕获组"><a href="#使用非捕获组" class="headerlink" title="使用非捕获组"></a>使用非捕获组</h3><p>NFA 正则引擎中的括号主要有两个作用:</p><ol><li><p>主流功能,提升括号中内容的运算优先级</p></li><li><p>反向引用</p></li></ol><p>反向引用这个功能很强大,强大的代价是消耗性能。所以,当我们如果不需要用到括号反向引用的功能时,我们应该尽量使用非捕获组,也就是:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 捕获组与非捕获组 </span><br><span class="line">() => (?:) </span><br></pre></td></tr></table></figure><h3 id="分支优化"><a href="#分支优化" class="headerlink" title="分支优化"></a>分支优化</h3><p>分支也是导致正则回溯的重要原因,所以,针对正则分支,我们也需要作出必要的优化。</p><p><strong>a. 减少分支数量</strong></p><p>首先,需要减少分支数量。比如不少正则在匹配 http 和 https 的时候喜欢写成:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/^http|https/ </span><br></pre></td></tr></table></figure><p>其实上面完全可以优化成:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/^https?/</span><br></pre></td></tr></table></figure><p>这样就能减少没必要的分支回溯</p><p><strong>b. 缩小分支内的内容</strong></p><p>缩小分支中的内容也是很有必要的,例如我们需要匹配 this 和 that ,我们也许会写成:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/this|that/</span><br></pre></td></tr></table></figure><p>但上面其实完全可以优化成:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/th(?:is|at)/</span><br></pre></td></tr></table></figure><p>有人可能认为以上没啥区别,实践出真知,让我们用以上两个正则表达式去匹配一下 that。</p><p>我们会发现第一个正则的执行步骤比第一个正则多两步,那是因为第一个正则的回溯路径比第二个正则的回溯路径更长了,最终导致执行步骤变长。</p><h3 id="锚点优化"><a href="#锚点优化" class="headerlink" title="锚点优化"></a>锚点优化</h3><p>在能使用锚点的情况下尽量使用锚点。大部分正则引擎会在编译阶段做些额外分析, 判断是否存在成功匹配必须的字符或者字符串。类似 ^、$ 这类锚点匹配能给正则引擎更多的优化信息。</p><p>例如正则表达式 hello(hi)?$ 在匹配过程中只可能从字符串末尾倒数第 7 个字符开始, 所以正则引擎能够分析跳到那个位置, 略过目标字符串中许多可能的字符, 大大提升匹配速度。</p><h3 id="RegexBuddy"><a href="#RegexBuddy" class="headerlink" title="RegexBuddy"></a>RegexBuddy</h3><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/2f57a694/RegexBuddy.jpg" alt="RegexBuddy"></p><p>性能优化完整版: <a href="https://www.zhihu.com/question/48219401/answer/1476436385">腾讯技术工程的知乎回答</a></p><h2 id="匹配中文"><a href="#匹配中文" class="headerlink" title="匹配中文"></a>匹配中文</h2><p>\w 匹配的仅仅是中文,数字,字母,对于国人来讲,仅匹配中文时常会用到,见下</p><p>中文汉字:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">匹配中文字符的正则表达式: [\u4e00-\u9fa5]</span><br></pre></td></tr></table></figure><p>双字节(包含中日韩等):</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">匹配双字节字符(包括汉字在内):[^\x00-\xff]</span><br></pre></td></tr></table></figure><h2 id="相关资源"><a href="#相关资源" class="headerlink" title="相关资源"></a>相关资源</h2><p><a href="https://regexper.com/">正则可视化 - regexper</a></p><p><a href="https://regexr.com/">在线测试 - regexr</a></p><p><a href="https://www.regexbuddy.com/">性能调试工具 - RegexBuddy</a></p><p><a href="https://www.cnblogs.com/zxin/archive/2013/01/26/2877765.html">最全的常用正则表达式大全</a></p>]]></content>
<summary type="html"><p>正则表达式(Regular Expression)是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。</p></summary>
<category term="IT技术" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/"/>
<category term="正则表达式" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/"/>
<category term="正则表达式" scheme="https://7bxing.com/tags/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/"/>
</entry>
<entry>
<title>✳️ Vi/Vim使用备忘</title>
<link href="https://7bxing.com/posts/b04c6f46/"/>
<id>https://7bxing.com/posts/b04c6f46/</id>
<published>2020-10-23T06:37:53.000Z</published>
<updated>2020-10-25T06:21:15.000Z</updated>
<content type="html"><![CDATA[<p>vi 是 linux 的内置文本编辑器<br>事实上,所有的 Unix Like 系统都会内建 vi文本编辑器</p><p>vim 则是 vi编辑器 的增强版本(支持语法高亮,方便程序设计,习惯上也称为vi),使用更广泛</p><span id="more"></span><h2 id="工作模式"><a href="#工作模式" class="headerlink" title="工作模式"></a>工作模式</h2><p>vi编辑器 有命令模式、输入模式、底线命令模式<br>我们通过 <code>vi 文件名</code> 的形式打开(或新建)文件进行编辑,如图所示:</p><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/b04c6f46/workmodel.png" alt="vim/vi工作模式"></p><p>结合图示介绍 vi编辑器 的三种工作模式,相当于图形软件窗口中的不同界面,不同的模式中能够对文件进行的操作也不相同</p><p>1)命令模式(Command mode):启动vi编辑器后默认进入命令模式,该模式中主要完成如光标移动、字符串查找,以及删除、复制、粘贴文件内容等相关操作</p><p>2)输入模式(Insert mode):该模式中主要的操作就是录入文件内容,可以对文本文件正文进行修改、或者添加新的内容。处于输入模式时,vi编辑器的最后一行会出现 <code>-- INSERT --</code> 的状态提示信息</p><p>3)底线命令模式(Last line mode):该模式中可以设置vi编辑环境、保存文件、退出编辑器,以及对文件内容进行查找、替换等操作。处于末行模式时,vi编辑器的最后一行会出现冒号 <code>:</code> 提示符</p><div class="tabs" id="tab-id"><ul class="nav-tabs"><li class="tab active"><a class="#tab-id-1">i、a、o等插入模式</a></li><li class="tab"><a class="#tab-id-2">具体区别</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tab-id-1"><p>插入模式则用来向文本中添加内容的,常用的是 i 和 o</p><p>i 在光标所在字符前开始输入文字并进入插入模式</p><p>o (字母 o) 在光标所在行的下面单独开一新行来输入文字并进入插入模式</p></div><div class="tab-pane" id="tab-id-2"><p>i 是在光标所在的字符之前插入需要录入的文本。<br>I 是在光标所在行的行首插入需要录入的文本。</p><p>a 是在光标所在的字符之后插入需要录入的文本。<br>A 是在光标所在行的行尾插入需要录入的文本。</p><p>o 是光标所在行的下一行行首插入需要录入的文本。<br>O 是光标所在行的上一行行首插入需要录入的文本。</p></div></div></div><p>补充说明:</p><div class="tabs" id="tab-id-2"><ul class="nav-tabs"><li class="tab active"><a class="#tab-id-2-1">宏录制</a></li><li class="tab"><a class="#tab-id-2-2">详细操作</a></li></ul><div class="tab-content"><div class="tab-pane active" id="tab-id-2-1"><p>特别地,命令模式按 <code>q</code> 会进入宏录制<br>非insert模式下输入 <code>q</code> 停止宏的录制</p><p><strong>此功能不是特别常用,但我们需要知道触发后怎么退出</strong></p></div><div class="tab-pane" id="tab-id-2-2"><ul><li>在命令模式下按下q键盘(此时左下角有“recording”这个标识)</li><li>选择a-z或0-9中任意一个作为缓冲器的名字,准备开始录制宏</li><li>正常的操作,此次所有的操作都会被记录在上一步中定义的缓冲器中</li><li>在非insert模式下输入q停止宏的录制</li><li>使用@ + 第二步中定义的缓冲器的名字即可</li></ul></div></div></div><h2 id="命令模式的基本操作"><a href="#命令模式的基本操作" class="headerlink" title="命令模式的基本操作"></a>命令模式的基本操作</h2><h3 id="光标移动"><a href="#光标移动" class="headerlink" title="光标移动"></a>光标移动</h3><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/b04c6f46/gbyd.png"></p><h3 id="复制、粘贴、删除"><a href="#复制、粘贴、删除" class="headerlink" title="复制、粘贴、删除"></a>复制、粘贴、删除</h3><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/b04c6f46/fuzhi-zt-sc.png"></p><h3 id="文件内容查找"><a href="#文件内容查找" class="headerlink" title="文件内容查找"></a>文件内容查找</h3><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/b04c6f46/wjnrcz.png"></p><h3 id="撤销编辑及保存退出"><a href="#撤销编辑及保存退出" class="headerlink" title="撤销编辑及保存退出"></a>撤销编辑及保存退出</h3><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/b04c6f46/chexiao-tc.png"></p><h3 id="保存文件及退出vi编辑器"><a href="#保存文件及退出vi编辑器" class="headerlink" title="保存文件及退出vi编辑器"></a>保存文件及退出vi编辑器</h3><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/b04c6f46/baocun-tc.png"></p><h3 id="打开新文件或读入其他文件内容"><a href="#打开新文件或读入其他文件内容" class="headerlink" title="打开新文件或读入其他文件内容"></a>打开新文件或读入其他文件内容</h3><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/b04c6f46/dakaixwnj.png"></p><h3 id="文件内容替换"><a href="#文件内容替换" class="headerlink" title="文件内容替换"></a>文件内容替换</h3><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/b04c6f46/wenjiannrth.png"></p><h2 id="其他常用"><a href="#其他常用" class="headerlink" title="其他常用"></a>其他常用</h2><h3 id="切换到后台"><a href="#切换到后台" class="headerlink" title="切换到后台"></a>切换到后台</h3><ul><li>CTRL+Z 挂起进程并放入后台</li><li>jobs 显示当前暂停的进程</li><li>bg %N 使第N个任务在后台运行(%前有空格)</li><li>fg %N 使第N个任务在前台运行</li></ul><blockquote><p>默认 bg,fg 不带 %N 时表示对最后一个进程操作!</p></blockquote><h3 id="多窗口操作"><a href="#多窗口操作" class="headerlink" title="多窗口操作"></a>多窗口操作</h3><p>水平方向 <code>:sp [filename]</code><br>垂直方向 <code>:vs [filename]</code></p><p>窗口切换 先按Ctrl+w,然后按方向键</p><blockquote><p>:qall 关闭所有文件quit all<br>:wall 写入所有文件write all</p></blockquote>]]></content>
<summary type="html"><p>vi 是 linux 的内置文本编辑器<br>事实上,所有的 Unix Like 系统都会内建 vi文本编辑器</p>
<p>vim 则是 vi编辑器 的增强版本(支持语法高亮,方便程序设计,习惯上也称为vi),使用更广泛</p></summary>
<category term="工具学习" scheme="https://7bxing.com/categories/%E5%B7%A5%E5%85%B7%E5%AD%A6%E4%B9%A0/"/>
<category term="Vim" scheme="https://7bxing.com/categories/%E5%B7%A5%E5%85%B7%E5%AD%A6%E4%B9%A0/Vim/"/>
<category term="Vim" scheme="https://7bxing.com/tags/Vim/"/>
</entry>
<entry>
<title>【推荐】Hexo博客配置及源文件备份</title>
<link href="https://7bxing.com/posts/659688f7/"/>
<id>https://7bxing.com/posts/659688f7/</id>
<published>2020-09-19T12:38:31.000Z</published>
<updated>2020-09-19T12:38:31.000Z</updated>
<content type="html"><![CDATA[<div class="note success"><p>利用 <code>批处理</code> + <code>坚果云</code> 来增量备份 Hexo 配置及源文件</p></div><span id="more"></span><h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>建站初期,经常折腾博客配置,有次不小心还误删除了 package.json,后来花费很久才重新配置完成。<br>又权衡了很久,决定要把配置和源文件备份起来!</p><p>于是乎,在网上搜索怎么备份 Hexo 配置及源文件?<br>大多都是直接或间接(通过插件)备份到 git仓库,而且操作相对复杂,感觉没必要</p><p>所以还是要研究自己的备份方法…</p><h2 id="需求点"><a href="#需求点" class="headerlink" title="需求点"></a>需求点</h2><p>整理一下:大致分为三个条件</p><ul><li>操作简单</li><li>增量备份</li><li>由于存在不少 key,必须满足私密性</li></ul><p>好在简单的 bat脚本 + 坚果云 就能实现</p><h2 id="操作步骤"><a href="#操作步骤" class="headerlink" title="操作步骤"></a>操作步骤</h2><p><em>以下是正文部分</em></p><h3 id="批处理复制到单独文件夹"><a href="#批处理复制到单独文件夹" class="headerlink" title="批处理复制到单独文件夹"></a>批处理复制到单独文件夹</h3><blockquote><p>xcopy命令可以增量复制(只复制改动过的文件)<br>需要复制的文件一般为package.json、_config.*yml、source和scaffolds<br>具体可以查看官方文档 <a href="https://hexo.io/zh-cn/docs/setup">hexo目录结构</a><br>或者其他更详细的介绍 <a href="https://segmentfault.com/a/1190000018237272">简单认识Hexo的目录结构</a></p></blockquote><p>bat脚本代码为:</p><figure class="highlight bat"><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></pre></td><td class="code"><pre><span class="line">@<span class="built_in">ECHO</span> OFF</span><br><span class="line"><span class="built_in">title</span> Hexo博客备份</span><br><span class="line"><span class="built_in">set</span> "<span class="built_in">Dir</span>=D:\Tools\!Hexo\"</span><br><span class="line"><span class="built_in">echo</span> -------------------------</span><br><span class="line"></span><br><span class="line">@<span class="built_in">ECHO</span> ON</span><br><span class="line"><span class="built_in">xcopy</span> /y /d %~nx0 "<span class="variable">%Dir%</span>"</span><br><span class="line"><span class="built_in">xcopy</span> /y /d package.json "<span class="variable">%Dir%</span>"</span><br><span class="line"><span class="built_in">xcopy</span> /y /d _config.*yml "<span class="variable">%Dir%</span>"</span><br><span class="line"><span class="built_in">xcopy</span> /y /d /e source "<span class="variable">%Dir%</span>source\"</span><br><span class="line"><span class="built_in">xcopy</span> /y /d /e scaffolds "<span class="variable">%Dir%</span>scaffolds\"</span><br><span class="line"></span><br><span class="line">@<span class="built_in">ECHO</span> OFF</span><br><span class="line"><span class="built_in">echo</span>.</span><br><span class="line"><span class="built_in">echo</span> -------------------------</span><br><span class="line"><span class="built_in">echo</span> 备份完成,按任意键退出...</span><br><span class="line"></span><br><span class="line"><span class="built_in">pause</span>><span class="built_in">nul</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>使用方法</strong>:<br>在博客根目录下,新建文本文档,改名为 <code>!copy.bat</code>,复制脚本代码,将 <code>D:\Tools\!Hexo\</code> 改为你的备份路径,保存<br>每次配置有调整或者新建了文章,点一下此脚本即可,效果如下:</p><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/659688f7/xcopy.png" alt="xcopy备份"></p><blockquote><p>注:如果你在源文件夹删除了某个文件或文件夹,此脚本就不能同步删除了,需要你去手动删除</p></blockquote><h3 id="备份到-坚果云"><a href="#备份到-坚果云" class="headerlink" title="备份到 坚果云"></a>备份到 <a href="https://www.jianguoyun.com/">坚果云</a></h3><p>其实没什么可说的(将bat脚本备份的文件夹同步到坚果云就行)<br>主要是强烈推荐一波 <code>坚果云</code></p><p>截两张图片吧:</p><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/659688f7/jianguoyun1.png" alt="每月流量"></p><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/659688f7/jianguoyun2.png" alt="文件历史版本"></p><p>最后,作为一个长期免费用户,衷心希望坚果云越做越好~</p>]]></content>
<summary type="html"><div class="note success"><p>利用 <code>批处理</code> + <code>坚果云</code> 来增量备份 Hexo 配置及源文件</p></div></summary>
<category term="Hexo" scheme="https://7bxing.com/categories/Hexo/"/>
<category term="Hexo备份" scheme="https://7bxing.com/tags/Hexo%E5%A4%87%E4%BB%BD/"/>
</entry>
<entry>
<title>「硬核JS」一次搞懂JS运行机制</title>
<link href="https://7bxing.com/posts/9c28944f/"/>
<id>https://7bxing.com/posts/9c28944f/</id>
<published>2020-09-08T14:15:55.000Z</published>
<updated>2020-09-08T14:15:55.000Z</updated>
<content type="html"><![CDATA[<p>从零到一百再到一,从多方面了解JS的运行机制,体会更深刻</p><span id="more"></span><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><blockquote><p>来自原作者的开场白:</p><p>从开始做前端到目前为止,陆续看了很多帖子讲JS运行机制,看过不久就忘了,还是自己理一遍好些<br>通过码字使自己对JS运行机制相关内容更加深刻(自己用心写过的贴子,内容也会牢记于心)<br>顺道给大家看看(我太难了,深夜码字,反复修改,说这么多就是想请你点个赞在看)<br>参考了很多资料(帖子),取其精华,去其糟糠,都在文末,可自行了解</p><p>是时候搞一波我大js了</p></blockquote><p>本文大致分为以下这样的步骤来帮助我们由广入深更加清晰的了解JS运行机制</p><ul><li>首先我们要了解进程和线程的概念</li><li>其次我们要知道浏览器的进程线程常识</li><li>再然后通过Event Loop、宏任务(macrotask)微任务(microtask)来看浏览器的几个线程间是怎样配合的</li><li>再然后通过例子来印证我们的猜想</li><li>最后提下NodeJS的运行机制</li></ul><h2 id="灵魂一问"><a href="#灵魂一问" class="headerlink" title="灵魂一问"></a>灵魂一问</h2><p>JS运行机制在平常前端面试时不管是笔试题还是面试题命中率都极高</p><p>说到JS运行机制,你知道多少</p><p>看到这大家可能回说:JS运行机制嘛,很简单,事件循环、宏微任务那点东西</p><p>是的,作为一名前端我们都了解,但是如果这真的面试问到了这个地方,你真的可以答好吗(灵魂一问️)</p><p><strong>不管你对JS了解多少,到这里大家不妨先停止一下阅读,假设你目前在面试,面试官让你阐述下JS运行机制,思考下你的答案,用20秒的时间(面试时20s已经很长了),然后带着答案再接着往下看,有人曾经说过:没有思考的阅读纯粹是消磨时间罢了,这话很好(因为是我说的,皮一下)</strong></p><p>也有很多刚开始接触JS的同学会被任务队列 执行栈 微任务 宏任务这些高大上点的名次搞的很懵</p><p>接下来,我们来细致的梳理一遍你就可以清晰的了解它们了</p><h2 id="进程与线程"><a href="#进程与线程" class="headerlink" title="进程与线程"></a>进程与线程</h2><h3 id="什么是进程"><a href="#什么是进程" class="headerlink" title="什么是进程"></a>什么是进程</h3><p>我们都知道,CPU是计算机的核心,承担所有的计算任务</p><p>官网说法,进程是CPU资源分配的最小单位</p><p>字面意思就是进行中的程序,我将它理解为一个可以独立运行且拥有自己的资源空间的任务程序</p><p>进程包括运行中的程序和程序所使用到的内存和系统资源</p><p>CPU可以有很多进程,我们的电脑每打开一个软件就会产生一个或多个进程,为什么电脑运行的软件多就会卡,是因为CPU给每个进程分配资源空间,但是一个CPU一共就那么多资源,分出去越多,越卡,每个进程之间是相互独立的,CPU在运行一个进程时,其他的进程处于非运行状态,CPU使用 时间片轮转调度算法 来实现同时运行多个进程</p><h3 id="什么是线程"><a href="#什么是线程" class="headerlink" title="什么是线程"></a>什么是线程</h3><p>线程是CPU调度的最小单位</p><p>线程是建立在进程的基础上的一次程序运行单位,通俗点解释线程就是程序中的一个执行流,一个进程可以有多个线程</p><p>一个进程中只有一个执行流称作单线程,即程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行</p><p>一个进程中有多个执行流称作多线程,即在一个程序中可以同时运行多个不同的线程来执行不同的任务, 也就是说允许单个程序创建多个并行执行的线程来完成各自的任务</p><h3 id="进程和线程的区别"><a href="#进程和线程的区别" class="headerlink" title="进程和线程的区别"></a>进程和线程的区别</h3><p>进程是操作系统分配资源的最小单位,线程是程序执行的最小单位</p><p>一个进程由一个或多个线程组成,线程可以理解为是一个进程中代码的不同执行路线</p><p>进程之间相互独立,但同一进程下的各个线程间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号)</p><p>调度和切换:线程上下文切换比进程上下文切换要快得多</p><h3 id="多进程和多线程"><a href="#多进程和多线程" class="headerlink" title="多进程和多线程"></a>多进程和多线程</h3><p>多进程:多进程指的是在同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态。多进程带来的好处是明显的,比如大家可以在网易云听歌的同时打开编辑器敲代码,编辑器和网易云的进程之间不会相互干扰</p><p>多线程:多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务</p><h3 id="JS为什么是单线程"><a href="#JS为什么是单线程" class="headerlink" title="JS为什么是单线程"></a>JS为什么是单线程</h3><p>JS的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?</p><p>还有人说js还有Worker线程,对的,为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程是完 全受主线程控制的,而且不得操作DOM</p><p>所以,这个标准并没有改变JavaScript是单线程的本质</p><p>了解了进程和线程之后,接下来看看浏览器解析,浏览器之间也是有些许差距的,不过大致是差不多的,下文我们皆用市场占有比例最大的Chrome为例</p><h2 id="浏览器"><a href="#浏览器" class="headerlink" title="浏览器"></a>浏览器</h2><h3 id="浏览器是多进程的"><a href="#浏览器是多进程的" class="headerlink" title="浏览器是多进程的"></a>浏览器是多进程的</h3><p>作为前端,免不了和浏览器打交道,浏览器是多进程的,拿Chrome来说,我们每打开一个Tab页就会产生一个进程,我们使用Chrome打开很多标签页不关,电脑会越来越卡,不说其他,首先就很耗CPU</p><h3 id="浏览器包含哪些进程"><a href="#浏览器包含哪些进程" class="headerlink" title="浏览器包含哪些进程"></a>浏览器包含哪些进程</h3><ul><li>Browser进程 浏览器的主进程(负责协调、主控),该进程只有一个 负责浏览器界面显示,与用户交互。如前进,后退等 负责各个页面的管理,创建和销毁其他进程 将渲染(Renderer)进程得到的内存中的Bitmap(位图),绘制到用户界面上 网络资源的管理,下载等</li><li>第三方插件进程 每种类型的插件对应一个进程,当使用该插件时才创建</li><li>GPU进程 该进程也只有一个,用于3D绘制等等</li><li>渲染进程(重) 即通常所说的浏览器内核(Renderer进程,内部是多线程) 每个Tab页面都有一个渲染进程,互不影响 主要作用为页面渲染,脚本执行,事件处理等</li></ul><h3 id="为什么浏览器要多进程"><a href="#为什么浏览器要多进程" class="headerlink" title="为什么浏览器要多进程"></a>为什么浏览器要多进程</h3><p>我们假设浏览器是单进程,那么某个Tab页崩溃了,就影响了整个浏览器,体验有多差</p><p>同理如果插件崩溃了也会影响整个浏览器</p><p>当然多进程还有其它的诸多优势,不过多阐述</p><p>浏览器进程有很多,每个进程又有很多线程,都会占用内存</p><p>这也意味着内存等资源消耗会很大,有点拿空间换时间的意思</p><p>到此可不只是为了让我们理解为何Chrome运行时间长了电脑会卡,哈哈,第一个重点来了</p><h3 id="简述渲染进程Renderer-重"><a href="#简述渲染进程Renderer-重" class="headerlink" title="简述渲染进程Renderer(重)"></a>简述渲染进程Renderer(重)</h3><p>页面的渲染,JS的执行,事件的循环,都在渲染进程内执行,所以我们要重点了解渲染进程</p><p>渲染进程是多线程的,我们来看渲染进程的一些常用较为主要的线程<br>渲染进程Renderer的主要线程</p><h3 id="GUI渲染线程"><a href="#GUI渲染线程" class="headerlink" title="GUI渲染线程"></a>GUI渲染线程</h3><ul><li>负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等 解析html代码(HTML代码本质是字符串)转化为浏览器认识的节点,生成DOM树,也就是DOM Tree 解析css,生成CSSOM(CSS规则树) 把DOM Tree 和CSSOM结合,生成Rendering Tree(渲染树)</li><li>当我们修改了一些元素的颜色或者背景色,页面就会重绘(Repaint)</li><li>当我们修改元素的尺寸,页面就会回流(Reflow)</li><li>当页面需要Repaing和Reflow时GUI线程执行,绘制页面</li><li>回流(Reflow)比重绘(Repaint)的成本要高,我们要尽量避免Reflow和Repaint</li><li>GUI渲染线程与JS引擎线程是互斥的 当JS引擎执行时GUI线程会被挂起(相当于被冻结了) GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行</li></ul><h3 id="JS引擎线程"><a href="#JS引擎线程" class="headerlink" title="JS引擎线程"></a>JS引擎线程</h3><ul><li>JS引擎线程就是JS内核,负责处理Javascript脚本程序(例如V8引擎)</li><li>JS引擎线程负责解析Javascript脚本,运行代码</li><li>JS引擎一直等待着任务队列中任务的到来,然后加以处理 浏览器同时只能有一个JS引擎线程在运行JS程序,所以js是单线程运行的 一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序</li><li>GUI渲染线程与JS引擎线程是互斥的,js引擎线程会阻塞GUI渲染线程 就是我们常遇到的JS执行时间过长,造成页面的渲染不连贯,导致页面渲染加载阻塞(就是加载慢) 例如浏览器渲染的时候遇到<code><script></code>标签,就会停止GUI的渲染,然后js引擎线程开始工作,执行里面的js代码,等js执行完毕,js引擎线程停止工作,GUI继续渲染下面的内容。所以如果js执行时间太长就会造成页面卡顿的情况</li></ul><h3 id="事件触发线程"><a href="#事件触发线程" class="headerlink" title="事件触发线程"></a>事件触发线程</h3><ul><li>属于浏览器而不是JS引擎,用来控制事件循环,并且管理着一个事件队列(task queue)</li><li>当js执行碰到事件绑定和一些异步操作(如setTimeOut,也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会走事件触发线程将对应的事件添加到对应的线程中(比如定时器操作,便把定时器事件添加到定时器线程),等异步事件有了结果,便把他们的回调操作添加到事件队列,等待js引擎线程空闲时来处理。</li><li>当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理</li><li>因为JS是单线程,所以这些待处理队列中的事件都得排队等待JS引擎处理</li></ul><h3 id="定时触发器线程"><a href="#定时触发器线程" class="headerlink" title="定时触发器线程"></a>定时触发器线程</h3><ul><li>setInterval与setTimeout所在线程</li><li>浏览器定时计数器并不是由JavaScript引擎计数的(因为JavaScript引擎是单线程的,如果处于阻塞线程状态就会影响记计时的准确)</li><li>通过单独线程来计时并触发定时(计时完毕后,添加到事件触发线程的事件队列中,等待JS引擎空闲后执行),这个线程就是定时触发器线程,也叫定时器线程</li><li>W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms</li></ul><h3 id="异步http请求线程"><a href="#异步http请求线程" class="headerlink" title="异步http请求线程"></a>异步http请求线程</h3><ul><li>在XMLHttpRequest在连接后是通过浏览器新开一个线程请求</li><li>将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中再由JavaScript引擎执行</li><li>简单说就是当执行到一个http异步请求时,就把异步请求事件添加到异步请求线程,等收到响应(准确来说应该是http状态变化),再把回调函数添加到事件队列,等待js引擎线程来执行</li></ul><p>了解了上面这些基础后,接下来我们开始进入今天的正题</p><h3 id="事件循环-Event-Loop-初探"><a href="#事件循环-Event-Loop-初探" class="headerlink" title="事件循环(Event Loop)初探"></a>事件循环(Event Loop)初探</h3><p>首先要知道,JS分为同步任务和异步任务</p><p>同步任务都在主线程(这里的主线程就是JS引擎线程)上执行,会形成一个执行栈</p><p>主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了运行结果,就在任务队列之中放一个事件回调</p><p>一旦执行栈中的所有同步任务执行完毕(也就是JS引擎线程空闲了),系统就会读取任务队列,将可运行的异步任务(任务队列中的事件回调,只要任务队列中有事件回调,就说明可以执行)添加到执行栈中,开始执行</p><p>我们来看一段简单的代码</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> setTimeoutCallBack = <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">'我是定时器回调'</span>);</span><br><span class="line">};</span><br><span class="line"><span class="keyword">let</span> httpCallback = <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">'我是http请求回调'</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="string">'我是同步任务1'</span>); <span class="comment">// 同步任务/</span></span><br><span class="line"><span class="built_in">setTimeout</span>(setTimeoutCallBack,<span class="number">1000</span>); <span class="comment">// 异步定时任务/</span></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment"> * 异步http请求任务</span></span><br><span class="line"><span class="comment"> * ajax.get('/info',httpCallback);//无此环境</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'我是同步任务2'</span>); <span class="comment">// 同步任务/</span></span><br></pre></td></tr></table></figure><p>上述代码执行过程</p><p>JS是按照顺序从上往下依次执行的,可以先理解为这段代码时的执行环境就是主线程,也就是也就是当前执行栈</p><p>首先,执行console.log(‘我是同步任务1’)</p><p>接着,执行到setTimeout时,会移交给定时器线程,通知定时器线程 1s 后将 setTimeoutCallBack 这个回调交给事件触发线程处理,在 1s 后事件触发线程会收到 setTimeoutCallBack 这个回调并把它加入到事件触发线程所管理的事件队列中等待执行</p><p>接着,执行http请求,会移交给异步http请求线程发送网络请求,请求成功后将 httpCallback 这个回调交由事件触发线程处理,事件触发线程收到 httpCallback 这个回调后把它加入到事件触发线程所管理的事件队列中等待执行</p><p>再接着执行console.log(‘我是同步任务2’)</p><p>至此主线程执行栈中执行完毕,JS引擎线程已经空闲,开始向事件触发线程发起询问,询问事件触发线程的事件队列中是否有需要执行的回调函数,如果有将事件队列中的回调事件加入执行栈中,开始执行回调,如果事件队列中没有回调,JS引擎线程会一直发起询问,直到有为止</p><p>到了这里我们发现,浏览器上的所有线程的工作都很单一且独立,非常符合单一原则</p><p>定时触发线程只管理定时器且只关注定时不关心结果,定时结束就把回调扔给事件触发线程</p><p>异步http请求线程只管理http请求同样不关心结果,请求结束把回调扔给事件触发线程</p><p>事件触发线程只关心异步回调入事件队列</p><p>而我们JS引擎线程只会执行执行栈中的事件,执行栈中的代码执行完毕,就会读取事件队列中的事件并添加到执行栈中继续执行,这样反反复复就是我们所谓的<strong>事件循环(Event Loop)</strong></p><p><strong>图解</strong></p><picture><source srcset="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/Event-Loop1.webp" type="image/webp"><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/Event-Loop1.jpg" /></picture><p>首先,执行栈开始顺序执行</p><p>判断是否为同步,异步则进入异步线程,最终事件回调给事件触发线程的任务队列等待执行,同步继续执行</p><p>执行栈空,询问任务队列中是否有事件回调</p><p>任务队列中有事件回调则把回调加入执行栈末尾继续从第一步开始执行</p><p>任务队列中没有事件回调则不停发起询问</p><h2 id="宏任务-macrotask-amp-微任务-microtask"><a href="#宏任务-macrotask-amp-微任务-microtask" class="headerlink" title="宏任务(macrotask) & 微任务(microtask)"></a>宏任务(macrotask) & 微任务(microtask)</h2><h3 id="宏任务-macrotask"><a href="#宏任务-macrotask" class="headerlink" title="宏任务(macrotask)"></a>宏任务(macrotask)</h3><p>在ECMAScript中,macrotask也被称为task</p><p>我们可以将每次执行栈执行的代码当做是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行), 每一个宏任务会从头到尾执行完毕,不会执行其他</p><p>由于JS引擎线程和GUI渲染线程是互斥的关系,浏览器为了能够使宏任务和DOM任务有序的进行,会在一个宏任务执行结果后,在下一个宏任务执行前,GUI渲染线程开始工作,对页面进行渲染</p><blockquote><p>宏任务 -> GUI渲染 -> 宏任务 -> …</p></blockquote><p>常见的宏任务</p><ul><li>主代码块</li><li>setTimeout</li><li>setInterval</li><li>setImmediate ()-Node</li><li>requestAnimationFrame ()-浏览器</li></ul><h3 id="微任务-microtask"><a href="#微任务-microtask" class="headerlink" title="微任务(microtask)"></a>微任务(microtask)</h3><p>ES6新引入了Promise标准,同时浏览器实现上多了一个microtask微任务概念,在ECMAScript中,microtask也被称为jobs</p><p>我们已经知道宏任务结束后,会执行渲染,然后执行下一个宏任务, 而微任务可以理解成在当前宏任务执行后立即执行的任务</p><p>当一个宏任务执行完,会在渲染前,将执行期间所产生的所有微任务都执行完</p><blockquote><p>宏任务 -> 微任务 -> GUI渲染 -> 宏任务 -> …</p></blockquote><p>常见微任务</p><ul><li>process.nextTick ()-Node</li><li>Promise.then()</li><li>catch</li><li>finally</li><li>Object.observe</li><li>MutationObserver</li></ul><h3 id="简单区分宏任务与微任务"><a href="#简单区分宏任务与微任务" class="headerlink" title="简单区分宏任务与微任务"></a>简单区分宏任务与微任务</h3><p>看了上述宏任务微任务的解释你可能还不太清楚,没关系,往下看,先记住那些常见的宏微任务即可</p><p>我们通过几个例子来看,这几个例子思路来自掘金云中君的文章参考链接<del>【14】</del>,通过渲染背景颜色来区分宏任务和微任务,很直观,我觉得很有意思,所以这里也用这种例子</p><p>找一个空白的页面,在console中输入以下代码</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span> = <span class="string">'background:black'</span>;</span><br><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span> = <span class="string">'background:red'</span>;</span><br><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span> = <span class="string">'background:blue'</span>;</span><br><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span> = <span class="string">'background:pink'</span>;</span><br></pre></td></tr></table></figure><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/test1.gif" alt="test1" title="test1"></p><p>我们看到上面动图背景直接渲染了粉红色,根据上文里讲浏览器会先执行完一个宏任务,再执行当前执行栈的所有微任务,然后移交GUI渲染,上面四行代码均属于同一次宏任务,全部执行完才会执行渲染,渲染时GUI线程会将所有UI改动优化合并,所以视觉上,只会看到页面变成粉红色</p><p>再接着看</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span> = <span class="string">'background:blue'</span>;</span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="function">()=></span>{</span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span> = <span class="string">'background:black'</span></span><br><span class="line">},<span class="number">200</span>)</span><br></pre></td></tr></table></figure><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/test2.gif" alt="test2" title="test2"></p><p>上述代码中,页面会先卡一下蓝色,再变成黑色背景,页面上写的是200毫秒,大家可以把它当成0毫秒,因为0毫秒的话由于浏览器渲染太快,录屏不好捕捉,我又没啥录屏慢放的工具,大家可以自行测试的,结果也是一样,最安全的方法是写一个index.html文件,在这个文件中插入上面的js脚本,然后浏览器打开,谷歌下使用控制台中performance功能查看一帧一帧的加载最为恰当,不过这样录屏不好录所以。。。</p><p>回归正题,之所以会卡一下蓝色,是因为以上代码属于两次宏任务,第一次宏任务执行的代码是将背景变成蓝色,然后触发渲染,将页面变成蓝色,再触发第二次宏任务将背景变成黑色</p><p>再来看</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span> = <span class="string">'background:blue'</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>);</span><br><span class="line"><span class="title class_">Promise</span>.<span class="title function_">resolve</span>().<span class="title function_">then</span>(<span class="function">()=></span>{</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>);</span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">style</span> = <span class="string">'background:pink'</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="number">3</span>);</span><br></pre></td></tr></table></figure><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/test3.gif" alt="test3"></p><p>控制台输出 1 3 2 , 是因为 promise 对象的 then 方法的回调函数是异步执行,所以 2 最后输出</p><p>页面的背景色直接变成粉色,没有经过蓝色的阶段,是因为,我们在宏任务中将背景设置为蓝色,但在进行渲染前执行了微任务, 在微任务中将背景变成了粉色,然后才执行的渲染</p><h3 id="微任务宏任务注意点"><a href="#微任务宏任务注意点" class="headerlink" title="微任务宏任务注意点"></a>微任务宏任务注意点</h3><ul><li>浏览器会先执行一个宏任务,紧接着执行当前执行栈产生的微任务,再进行渲染,然后再执行下一个宏任务</li><li>微任务和宏任务不在一个任务队列,不在一个任务队列 例如setTimeout是一个宏任务,它的事件回调在宏任务队列,Promise.then()是一个微任务,它的事件回调在微任务队列,二者并不是一个任务队列 以Chrome 为例,有关渲染的都是在渲染进程中执行,渲染进程中的任务(DOM树构建,js解析…等等)需要主线程执行的任务都会在主线程中执行,而浏览器维护了一套事件循环机制,主线程上的任务都会放到消息队列中执行,主线程会循环消息队列,并从头部取出任务进行执行,如果执行过程中产生其他任务需要主线程执行的,渲染进程中的其他线程会把该任务塞入到消息队列的尾部,消息队列中的任务都是宏任务 微任务是如何产生的呢?当执行到script脚本的时候,js引擎会为全局创建一个执行上下文,在该执行上下文中维护了一个微任务队列,当遇到微任务,就会把微任务回调放在微队列中,当所有的js代码执行完毕,在退出全局上下文之前引擎会去检查该队列,有回调就执行,没有就退出执行上下文,这也就是为什么微任务要早于宏任务,也是大家常说的,每个宏任务都有一个微任务队列(由于定时器是浏览器的API,所以定时器是宏任务,在js中遇到定时器会也是放入到浏览器的队列中)</li></ul><p>此时,你可能还很迷惑,没关系,请接着往下看</p><h3 id="图解宏任务和微任务"><a href="#图解宏任务和微任务" class="headerlink" title="图解宏任务和微任务"></a>图解宏任务和微任务</h3><picture><source srcset="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/Event-Loop2.webp" type="image/webp"><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/Event-Loop2.jpg" /></picture><p>首先执行一个宏任务,执行结束后判断是否存在微任务</p><p>有微任务先执行所有的微任务,再渲染,没有微任务则直接渲染</p><p>然后再接着执行下一个宏任务</p><h3 id="图解完整的Event-Loop"><a href="#图解完整的Event-Loop" class="headerlink" title="图解完整的Event Loop"></a>图解完整的Event Loop</h3><picture><source srcset="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/Event-Loop_wz.webp" type="image/webp"><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/Event-Loop_wz.jpg" /></picture><p>首先,整体的script(作为第一个宏任务)开始执行的时候,会把所有代码分为同步任务、异步任务两部分</p><p>同步任务会直接进入主线程依次执行</p><p>异步任务会再分为宏任务和微任务</p><p>宏任务进入到Event Table中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到Event Queue中</p><p>微任务也会进入到另一个Event Table中,并在里面注册回调函数,每当指定的事件完成时,Event Table会将这个函数移到Event Queue中</p><p>当主线程内的任务执行完毕,主线程为空时,会检查微任务的Event Queue,如果有任务,就全部执行,如果没有就执行下一个宏任务</p><p>上述过程会不断重复,这就是Event Loop,比较完整的事件循环</p><h3 id="关于Promise"><a href="#关于Promise" class="headerlink" title="关于Promise"></a>关于Promise</h3><p>new Promise(() => {}).then() ,我们来看这样一个Promise代码</p><p>前面的 new Promise() 这一部分是一个构造函数,这是一个同步任务</p><p>后面的 .then() 才是一个异步微任务,这一点是非常重要的</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">Promise</span>((resolve) = > {</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>)</span><br><span class="line"><span class="title function_">resolve</span>()</span><br><span class="line">}).<span class="title function_">then</span>(() = > {</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</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="number">3</span>)</span><br></pre></td></tr></table></figure><p>上面代码输出1 3 2</p><h3 id="关于-async-x2F-await-函数"><a href="#关于-async-x2F-await-函数" class="headerlink" title="关于 async/await 函数"></a>关于 async/await 函数</h3><p>async/await本质上还是基于Promise的一些封装,而Promise是属于微任务的一种</p><p>所以在使用await关键字与Promise.then效果类似</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =></span> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">4</span>))</span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">test</span>(<span class="params"></span>) {</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">await</span> <span class="title class_">Promise</span>.<span class="title function_">resolve</span>()</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">3</span>)</span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>()</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>)</span><br></pre></td></tr></table></figure><p>上述代码输出1 2 3 4</p><p>可以理解为,await 以前的代码,相当于与 new Promise 的同步代码,await 以后的代码相当于 Promise.then的异步</p><h3 id="举栗印证"><a href="#举栗印证" class="headerlink" title="举栗印证"></a>举栗印证</h3><p>首先给大家来一个比较直观的动图<br><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/lizi.gif" title="lizi"></p><p>之所以放这个动图,就是为了向大家推荐这篇好文,动图录屏自参考链接【1】</p><p>极力推荐大家看看这篇帖子,非常nice,分步动画生动且直观,有时间的话可以自己去体验下</p><p>不过在看这个帖子之前你要先了解下运行机制会更好读懂些</p><p>接下来这个来自网上随意找的一个比较简单的面试题,求输出结果</p><figure class="highlight js"><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">function</span> <span class="title function_">test</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">1</span>)</span><br><span class="line"> <span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) { <span class="comment">// timer1</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span>)</span><br><span class="line"> }, <span class="number">1000</span>)</span><br><span class="line">}</span><br><span class="line"><span class="title function_">test</span>();</span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) { <span class="comment">// timer2</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">3</span>)</span><br><span class="line">})</span><br><span class="line"><span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="keyword">function</span> (<span class="params">resolve</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">4</span>)</span><br><span class="line"> <span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) { <span class="comment">// timer3</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">5</span>)</span><br><span class="line"> }, <span class="number">100</span>)</span><br><span class="line"> <span class="title function_">resolve</span>()}).<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="built_in">setTimeout</span>(<span class="keyword">function</span> (<span class="params"></span>) { <span class="comment">// timer4</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">6</span>)</span><br><span class="line"> }, <span class="number">0</span>)</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">7</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="number">8</span>)</span><br></pre></td></tr></table></figure><p>结合我们上述的JS运行机制再来看这道题就简单明了的多了</p><p>JS是顺序从上而下执行</p><p>执行到test(),test方法为同步,直接执行,console.log(1)打印1</p><p>test方法中setTimeout为异步宏任务,回调我们把它记做timer1放入宏任务队列</p><p>接着执行,test方法下面有一个setTimeout为异步宏任务,回调我们把它记做timer2放入宏任务队列</p><p>接着执行promise,new Promise是同步任务,直接执行,打印4</p><p>new Promise里面的setTimeout是异步宏任务,回调我们记做timer3放到宏任务队列</p><p>Promise.then是微任务,放到微任务队列</p><p>console.log(8)是同步任务,直接执行,打印8</p><p>主线程任务执行完毕,检查微任务队列中有Promise.then</p><p>开始执行微任务,发现有setTimeout是异步宏任务,记做timer4放到宏任务队列</p><p>微任务队列中的console.log(7)是同步任务,直接执行,打印7</p><p>微任务执行完毕,第一次循环结束</p><p>检查宏任务队列,里面有timer1、timer2、timer3、timer4,四个定时器宏任务,按照定时器延迟时间得到可以执行的顺序,即Event Queue:timer2、timer4、timer3、timer1,依次拿出放入执行栈末尾执行 (插播一条:浏览器 event loop 的 Macrotask queue,就是宏任务队列在每次循环中只会读取一个任务)</p><p>执行timer2,console.log(3)为同步任务,直接执行,打印3</p><p>检查没有微任务,第二次结束</p><p>执行timer4,console.log(6)为同步任务,直接执行,打印6</p><p>检查没有微任务,第三次Event Loop结束</p><p>执行timer3,console.log(5)同步任务,直接执行,打印5</p><p>检查没有微任务,第四次Event Loop结束</p><p>执行timer1,console.log(2)同步任务,直接执行,打印2</p><p>检查没有微任务,也没有宏任务,第五次Event Loop结束</p><p>结果:1,4,8,7,3,6,5,2</p><h2 id="提一下NodeJS中的运行机制"><a href="#提一下NodeJS中的运行机制" class="headerlink" title="提一下NodeJS中的运行机制"></a>提一下NodeJS中的运行机制</h2><p>上面的一切都是针对于浏览器的EventLoop</p><p>虽然NodeJS中的JavaScript运行环境也是V8,也是单线程,但是,还是有一些与浏览器中的表现是不一样的</p><p>其实nodejs与浏览器的区别,就是nodejs的宏任务分好几种类型,而这好几种又有不同的任务队列,而不同的任务队列又有顺序区别,而微任务是穿插在每一种宏任务之间的</p><p>在node环境下,process.nextTick的优先级高于Promise,可以简单理解为在宏任务结束后会先执行微任务队列中的nextTickQueue部分,然后才会执行微任务中的Promise部分</p><picture><source srcset="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/nodejs.webp" type="image/webp"><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/9c28944f/nodejs.jpg" /></picture><p>上图来自NodeJS官网</p><p>如上图所示,nodejs的宏任务分好几种类型,我们只简单介绍大体内容了解,不详细解释,不然又是啰哩啰嗦一大篇</p><p>NodeJS的Event Loop相对比较麻烦</p><blockquote><p>Node会先执行所有类型为 timers 的 MacroTask,然后执行所有的 MicroTask(NextTick例外)<br>进入 poll 阶段,执行几乎所有 MacroTask,然后执行所有的 MicroTask再执行所有类型为 check 的 MacroTask,然后执行所有的 MicroTask<br>再执行所有类型为 close callbacks 的 MacroTask,然后执行所有的 MicroTask<br>至此,完成一个 Tick,回到 timers 阶段……如此反复,无穷无尽……</p></blockquote><p>反观浏览器中Event Loop就比较容易理解</p><blockquote><p>先执行一个 MacroTask,然后执行所有的 MicroTask<br>再执行一个 MacroTask,然后执行所有的 MicroTask……如此反复,无穷无尽……</p></blockquote><p>好了,关于Node中各个类型阶段的解析,这里就不过多说明了,自己查阅资料吧,这里就是简单提一下,NodeJS的Event Loop解释起来比浏览器这繁杂,这里就只做个对比</p><h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2><p>本文转载自今日头条创作者<a href="https://www.toutiao.com/c/user/50015307320/">Echa攻城狮</a>,感谢!</p><p>原文链接: <a href="https://www.toutiao.com/i6805366747240071693/">「硬核JS」一次搞懂JS运行机制</a></p>]]></content>
<summary type="html"><p>从零到一百再到一,从多方面了解JS的运行机制,体会更深刻</p></summary>
<category term="IT技术" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/"/>
<category term="JavaScript" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/JavaScript/"/>
<category term="JavaScript" scheme="https://7bxing.com/tags/JavaScript/"/>
</entry>
<entry>
<title>2016美国总统候选人辩论</title>
<link href="https://7bxing.com/posts/52bf0210/"/>
<id>https://7bxing.com/posts/52bf0210/</id>
<published>2020-08-27T04:42:41.000Z</published>
<updated>2020-08-27T04:42:41.000Z</updated>
<content type="html"><![CDATA[<div class="note radiation"><p>2016美国总统候选人辩论,共三场 <br>电视辩论,特朗普对决希拉里</p></div><span id="more"></span><div style="display: none"><h2 id="观看视频"><a href="#观看视频" class="headerlink" title="观看视频"></a>观看视频</h2></div><div class="tabs" id="bianlun"><ul class="nav-tabs"><li class="tab active"><a class="#bianlun-1">第一场</a></li><li class="tab"><a class="#bianlun-2"><del>第二场</del></a></li><li class="tab"><a class="#bianlun-3"><del>第三场</del></a></li><li class="tab"><a class="#bianlun-4">TODO</a></li></ul><div class="tab-content"><div class="tab-pane active" id="bianlun-1"><div class="ixigua"> <iframe src="https://www.ixigua.com/embed?group_id=6858053317222728204" width="100%" height="300" frameborder="0" loading="lazy" allowfullscreen></iframe></div></div><div class="tab-pane" id="bianlun-2"><p>请从下方原始链接观看~</p><!-- <div class="video"><video controls preload><source src='https://v3-xg-web.ixigua.com/67c60ae039b7053bbb0dfb65171d2149/5f47b19a/video/tos/cn/tos-cn-ve-4/da325f5138cb4460aebef570838336a9/?a=1768' type='video/mp4'>Your browser does not support the video tag.</video></div> --></div><div class="tab-pane" id="bianlun-3"><p>请从下方原始链接观看~</p><!-- <div class="video"><video controls preload><source src='https://v3-xg-web.ixigua.com/1284553a7ca9b081e8b1da860f4e066c/5f47b1a1/video/tos/cn/tos-cn-ve-4/2a14ab59ac2d421196a018bec7c05ea5/?a=1768' type='video/mp4'>Your browser does not support the video tag.</video></div> --></div><div class="tab-pane" id="bianlun-4"><blockquote><p>如果感兴趣<br>请从下方原始链接观看第二场和第三场~</p></blockquote><p>备注:页面嵌套多个西瓜视频会非常卡顿(多个视频也会同时播放)<br>事实上,只嵌套一个时 也有报错(官方的iframe还处于开发模式)<br>而B站的该视频第二场,清晰度最高只有480p</p></div></div></div><h2 id="转载出处"><a href="#转载出处" class="headerlink" title="转载出处"></a>转载出处</h2><blockquote><p>视频来源: <a href="https://www.ixigua.com/">西瓜视频</a><br>作者: <a href="https://www.ixigua.com/home/100451137325/pseries/?preActiveKey=home">波涛学时</a></p></blockquote><p>原文链接:</p><span class='btn regular'><a class="button" href='https://www.ixigua.com/6858053317222728204' title='第一场'><i class='fas fa-play-circle'></i>第一场</a></span><span class='btn regular'><a class="button" href='https://www.ixigua.com/6857097688618369548' title='第二场'><i class='fas fa-play-circle'></i>第二场</a></span><span class='btn regular'><a class="button" href='https://www.ixigua.com/6855980266113106445' title='第三场'><i class='fas fa-play-circle'></i>第三场</a></span>]]></content>
<summary type="html"><div class="note radiation"><p>2016美国总统候选人辩论,共三场 <br>电视辩论,特朗普对决希拉里</p></div></summary>
<category term="未分类" scheme="https://7bxing.com/categories/%E6%9C%AA%E5%88%86%E7%B1%BB/"/>
<category term="其他" scheme="https://7bxing.com/tags/%E5%85%B6%E4%BB%96/"/>
</entry>
<entry>
<title>短网址生成</title>
<link href="https://7bxing.com/posts/991130e/"/>
<id>https://7bxing.com/posts/991130e/</id>
<published>2020-07-12T05:46:41.000Z</published>
<updated>2020-07-14T06:48:16.000Z</updated>
<content type="html"><![CDATA[<p>基于 <del><a href="https://suowo.cn/">suowo.cn</a></del>(开始弹广告了…) 官方API制作的 <code>短网址生成</code> 的小书签和快捷指令</p><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/991130e/xiaoshuqian.png" alt="小书签版运行截图"></p><span id="more"></span><h2 id="安装说明"><a href="#安装说明" class="headerlink" title="安装说明"></a>安装说明</h2><ul><li>小书签: <a href="https://www.runningcheese.com/bookmarklet">教程说明</a></li></ul><blockquote><p>使用了ES6语法,不兼容IE浏览器<br>如果需要批量处理,请到官网处理(或采用其他工具, 推荐 <a href="http://suo.im/5XOyoQ">Short Url</a>)</p></blockquote><ul><li>IOS捷径: <a href="https://www.rcuts.com/382.html">首次安装使用教程</a></li></ul><p><strong>强烈建议: 安装后申请个人的 <a href="https://suowo.cn/" title="前往申请">key</a> , 并进行手动替换</strong></p><details ><summary> 小书签替换key </summary> <div class='content'> <p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/991130e/tihuan_xsq_key.png"></p> </div> </details><details ><summary> IOS捷径替换key </summary> <div class='content'> <p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/991130e/tihuan_jj_key.png"></p> </div> </details><h2 id="js小书签"><a href="#js小书签" class="headerlink" title="js小书签"></a>js小书签</h2><details green><summary> 小书签代码 </summary> <div class='content'> <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></pre></td><td class="code"><pre><span class="line"><span class="attr">javascript</span>:(<span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="string">'use strict'</span>;</span><br><span class="line"> <span class="keyword">const</span> suo_now = <span class="literal">true</span>; <span class="comment">/*打开时直接压缩window.location.href*/</span></span><br><span class="line"> <span class="keyword">const</span> suo_api = <span class="string">'https://api.suowo.cn/api.htm'</span>;</span><br><span class="line"> <span class="keyword">const</span> suo_key = <span class="string">'5f0729c5b1b63c45d0cb8173@ae63a2ad212f6e56088ab7814732c4c0'</span>;</span><br><span class="line"> <span class="keyword">const</span> <span class="title function_">dq</span> = css => <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(css);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> suoIm = {</span><br><span class="line"> <span class="attr">show</span>: <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">let</span> content = <span class="string">'也可以输入长网址:'</span>;</span><br><span class="line"> <span class="keyword">let</span> css = <span class="string">`<style></span></span><br><span class="line"><span class="string"> .dialog-container {</span></span><br><span class="line"><span class="string"> position: fixed;</span></span><br><span class="line"><span class="string"> top: 0;</span></span><br><span class="line"><span class="string"> width: 40%;</span></span><br><span class="line"><span class="string"> min-width:300px;</span></span><br><span class="line"><span class="string"> margin: 0 auto;</span></span><br><span class="line"><span class="string"> border: 1px solid #ddd;</span></span><br><span class="line"><span class="string"> border-radius: 4px;</span></span><br><span class="line"><span class="string"> background-color: #fff;</span></span><br><span class="line"><span class="string"> font: 14px/1.5 -apple-system,'Microsoft Yahei';</span></span><br><span class="line"><span class="string"> z-index: 99999;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> .ctrlV-content {padding: 10px;}</span></span><br><span class="line"><span class="string"> .bm-btns {</span></span><br><span class="line"><span class="string"> float: right;</span></span><br><span class="line"><span class="string"> margin-right: 20px;</span></span><br><span class="line"><span class="string"> margin-bottom: 10px;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> .long-url {</span></span><br><span class="line"><span class="string"> display: block;</span></span><br><span class="line"><span class="string"> width: 98%;</span></span><br><span class="line"><span class="string"> margin-top: 10px;</span></span><br><span class="line"><span class="string"> padding-left: 0.3em;</span></span><br><span class="line"><span class="string"> border: 1px solid #ddd;</span></span><br><span class="line"><span class="string"> border-radius: 4px;</span></span><br><span class="line"><span class="string"> line-height: 28px;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> .mybtn {</span></span><br><span class="line"><span class="string"> margin-right: 6px;</span></span><br><span class="line"><span class="string"> padding: 0 12px !important;</span></span><br><span class="line"><span class="string"> border: none;</span></span><br><span class="line"><span class="string"> border-radius: 10px;</span></span><br><span class="line"><span class="string"> background: #981a1a;</span></span><br><span class="line"><span class="string"> color: #fff;</span></span><br><span class="line"><span class="string"> letter-spacing: .5em;</span></span><br><span class="line"><span class="string"> text-indent: .5em;</span></span><br><span class="line"><span class="string"> font-size: 14px;</span></span><br><span class="line"><span class="string"> line-height: 27.5px;</span></span><br><span class="line"><span class="string"> }</span></span><br><span class="line"><span class="string"> .mybtn:hover {background-color: #0371df !important;}</span></span><br><span class="line"><span class="string"> #cancel {background: #2d2d2d;}</span></span><br><span class="line"><span class="string"> </style>`</span>;</span><br><span class="line"> <span class="keyword">let</span> html = <span class="string">`</span></span><br><span class="line"><span class="string"> <div class='dialog-container'></span></span><br><span class="line"><span class="string"> <div class='ctrlV-content'><span class="subst">${content}</span></span></span><br><span class="line"><span class="string"> <input class='long-url' value='' placeholder='为空则默认为当前网址'></span></span><br><span class="line"><span class="string"> </div></span></span><br><span class="line"><span class="string"> <div class='bm-btns'></span></span><br><span class="line"><span class="string"> <button id='operation' class='mybtn'><span class="subst">${suo_now?<span class="string">'清空'</span>:<span class="string">'生成'</span>}</span></button></span></span><br><span class="line"><span class="string"> <button id='copy' class='mybtn'>复制</button></span></span><br><span class="line"><span class="string"> <button id='cancel' class='mybtn'>取消</button></span></span><br><span class="line"><span class="string"> </div></span></span><br><span class="line"><span class="string"> </div></span></span><br><span class="line"><span class="string"> `</span>;</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'head'</span>).<span class="title function_">insertAdjacentHTML</span>(<span class="string">'beforeend'</span>, css);</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'body'</span>).<span class="title function_">insertAdjacentHTML</span>(<span class="string">'beforeend'</span>, html);</span><br><span class="line"> <span class="built_in">setTimeout</span>(<span class="function">() =></span> {</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'.long-url'</span>).<span class="title function_">focus</span>();</span><br><span class="line"> }, <span class="number">50</span>);</span><br><span class="line"> <span class="keyword">let</span> screenWidth = <span class="variable language_">window</span>.<span class="property">screen</span>.<span class="property">width</span>;</span><br><span class="line"> <span class="keyword">let</span> _left = (screenWidth - (<span class="title function_">dq</span>(<span class="string">'.dialog-container'</span>).<span class="property">offsetWidth</span>)) / <span class="number">2</span>;</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'.dialog-container'</span>).<span class="property">style</span>.<span class="property">marginLeft</span> = _left + <span class="string">'px'</span>;</span><br><span class="line"> suo_now && <span class="variable language_">this</span>.<span class="title function_">shortUrl</span>(<span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span>);</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'.bm-btns'</span>).<span class="title function_">addEventListener</span>(<span class="string">'click'</span>, <span class="variable language_">this</span>.<span class="property">handle</span>);</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="attr">handle</span>: <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">if</span> (!event.<span class="property">target</span>.<span class="property">id</span>) <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">let</span> url = <span class="title function_">dq</span>(<span class="string">'.long-url'</span>).<span class="property">value</span> || <span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span>;</span><br><span class="line"> <span class="keyword">let</span> button = event.<span class="property">target</span>.<span class="property">id</span>;</span><br><span class="line"> <span class="keyword">let</span> oldText = event.<span class="property">target</span>.<span class="property">innerText</span>;</span><br><span class="line"> <span class="keyword">if</span> (button == <span class="string">'operation'</span>){</span><br><span class="line"> <span class="keyword">if</span> (oldText==<span class="string">'生成'</span>) {</span><br><span class="line"> suoIm.<span class="title function_">shortUrl</span>(url);</span><br><span class="line"> event.<span class="property">target</span>.<span class="property">innerText</span> = <span class="string">'清空'</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'.long-url'</span>).<span class="property">value</span> = <span class="string">''</span>;</span><br><span class="line"> event.<span class="property">target</span>.<span class="property">innerText</span> = <span class="string">'生成'</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (button == <span class="string">'copy'</span> && !<span class="title function_">dq</span>(<span class="string">'.long-url'</span>).<span class="property">value</span>){</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'.long-url'</span>).<span class="title function_">setAttribute</span>(<span class="string">'placeholder'</span>,<span class="string">'请先点 [生成] 后再复制'</span>);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'.dialog-container'</span>).<span class="title function_">remove</span>();</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'style:last-child'</span>).<span class="title function_">remove</span>();</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> </span><br><span class="line"> <span class="attr">shortUrl</span>: <span class="keyword">function</span>(<span class="params">long_url</span>) {</span><br><span class="line"> <span class="comment">/*</span></span><br><span class="line"><span class="comment"> let long_url = 'https://www.bilibili.com/video/BV1EW411u7th?p=1';</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="variable language_">this</span>.<span class="title function_">jsonp</span>({</span><br><span class="line"> <span class="attr">format</span>:<span class="string">'jsonp'</span>,</span><br><span class="line"> <span class="attr">key</span>: suo_key,</span><br><span class="line"> <span class="attr">expireDate</span>:<span class="string">'2030-03-31'</span>,</span><br><span class="line"> <span class="attr">url</span>: <span class="built_in">encodeURIComponent</span>(long_url)</span><br><span class="line"> },<span class="string">'jsoncallback'</span>);</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="attr">jsonp</span>: <span class="keyword">function</span>(<span class="params">data, callback</span>) {</span><br><span class="line"> <span class="keyword">let</span> queryString = <span class="string">'?'</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">let</span> k <span class="keyword">in</span> data){</span><br><span class="line"> queryString += k + <span class="string">'='</span> + data[k] + <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="keyword">let</span> _url = suo_api + queryString + <span class="string">'callback='</span> + callback; </span><br><span class="line"> <span class="keyword">let</span> head = <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">'head'</span>)[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">let</span> script = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">'script'</span>);</span><br><span class="line"> head.<span class="title function_">appendChild</span>(script);</span><br><span class="line"> <span class="comment">/*创建jsonp回调函数*/</span></span><br><span class="line"> <span class="variable language_">window</span>[callback] = <span class="function"><span class="params">json</span> =></span> {</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'.long-url'</span>).<span class="property">value</span> = json.<span class="property">url</span>;</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'.long-url'</span>).<span class="title function_">select</span>();</span><br><span class="line"> <span class="title function_">dq</span>(<span class="string">'#copy'</span>).<span class="title function_">addEventListener</span>(<span class="string">'click'</span>, <span class="variable language_">this</span>.<span class="property">copyText</span>);</span><br><span class="line"> head.<span class="title function_">removeChild</span>(script);</span><br><span class="line"> <span class="variable language_">window</span>[callback] = <span class="literal">null</span>;</span><br><span class="line"> };</span><br><span class="line"> <span class="comment">/*发送请求*/</span></span><br><span class="line"> script.<span class="property">src</span> = _url;</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> <span class="attr">copyText</span>: <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">let</span> ele = <span class="title function_">dq</span>(<span class="string">'.long-url'</span>);</span><br><span class="line"> <span class="keyword">if</span> (navigator.<span class="property">userAgent</span>.<span class="title function_">match</span>(<span class="regexp">/ipad|iphone/i</span>)) {</span><br><span class="line"> <span class="keyword">let</span> range = <span class="variable language_">document</span>.<span class="title function_">createRange</span>();</span><br><span class="line"> range.<span class="title function_">selectNode</span>(ele);</span><br><span class="line"> <span class="variable language_">window</span>.<span class="title function_">getSelection</span>().<span class="title function_">addRange</span>(range);</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">execCommand</span>(<span class="string">'copy'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/*Remove the selections - <span class="doctag">NOTE:</span> Should use*/</span></span><br><span class="line"> <span class="variable language_">window</span>.<span class="title function_">getSelection</span>().<span class="title function_">removeAllRanges</span>();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> ele.<span class="title function_">focus</span>();</span><br><span class="line"> ele.<span class="title function_">select</span>();</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">execCommand</span>(<span class="string">'copy'</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"> suoIm.<span class="title function_">show</span>();</span><br><span class="line"></span><br><span class="line">})();</span><br></pre></td></tr></table></figure> </div> </details><!-- - [运行](javascript:dwz()) --><ul><li>测试: <i class="fa fa-angle-double-right"></i> <a href="javascript:(function(){'use%20strict';const%20suo_now=true;const%20suo_api='https://api.suowo.cn/api.htm';const%20suo_key='5f0729c5b1b63c45d0cb8173@ae63a2ad212f6e56088ab7814732c4c0';const%20dq=css=>document.querySelector(css);let%20suoIm={show:function(){let%20content='也可以输入长网址:';let%20css=`<style>.dialog-container{position:fixed;top:0;width:40%;min-width:300px;margin:0%20auto;border:1px%20solid#ddd;border-radius:4px;background-color:#fff;font:14px/1.5%20-apple-system,'Microsoft%20Yahei';z-index:99999}.ctrlV-content{padding:10px}.bm-btns{float:right;margin-right:20px;margin-bottom:10px;}.long-url{display:block;width:98%;margin-top:10px;padding-left:0.3em;border:1px%20solid#ddd;border-radius:4px;line-height:28px}.mybtn{margin-right:6px;padding:0%2010px!important;border:none;border-radius:10px;background:#981a1a;color:#fff;letter-spacing:.5em;text-indent:.5em;font-size:14px;line-height:27.5px;}.mybtn:hover{background-color:#0371df!important}#cancel{background:#2d2d2d}</style>`;let%20html=`<div%20class='dialog-container'><div%20class='ctrlV-content'>${content}<input%20class='long-url'value=''placeholder='为空则默认为当前网址'></div><div%20class='bm-btns'><button%20id='operation'class='mybtn'>${suo_now?'清空':'生成'}</button><button%20id='copy'class='mybtn'>复制</button><button%20id='cancel'class='mybtn'>取消</button></div></div>`;dq('head').insertAdjacentHTML('beforeend',css);dq('body').insertAdjacentHTML('beforeend',html);setTimeout(()=>{dq('.long-url').focus()},50);let%20screenWidth=window.screen.width;let%20_left=(screenWidth-(dq('.dialog-container').offsetWidth))/2;dq('.dialog-container').style.marginLeft=_left+'px';suo_now&&this.shortUrl(window.location.href);dq('.bm-btns').addEventListener('click',this.handle)},handle:function(){if(!event.target.id)return;let%20url=dq('.long-url').value||window.location.href;let%20button=event.target.id;let%20oldText=event.target.innerText;if(button=='operation'){if(oldText=='生成'){suoIm.shortUrl(url);event.target.innerText='清空'}else{dq('.long-url').value='';event.target.innerText='生成'}}else{if(button=='copy'&&!dq('.long-url').value){dq('.long-url').setAttribute('placeholder','请先点%20[生成]%20后再复制');return}dq('.dialog-container').remove();dq('style:last-child').remove()}},shortUrl:function(long_url){this.jsonp({format:'jsonp',key:suo_key,expireDate:'2030-03-31',url:encodeURIComponent(long_url)},'jsoncallback')},jsonp:function(data,callback){let%20queryString='?';for(let%20k%20in%20data){queryString+=k+'='+data[k]+'&'}let%20_url=suo_api+queryString+'callback='+callback;let%20head=document.getElementsByTagName('head')[0];let%20script=document.createElement('script');head.appendChild(script);window[callback]=json=>{dq('.long-url').value=json.url;dq('.long-url').select();dq('#copy').addEventListener('click',this.copyText);head.removeChild(script);window[callback]=null};script.src=_url},copyText:function(){let%20ele=dq('.long-url');if(navigator.userAgent.match(/ipad|iphone/i)){let%20range=document.createRange();range.selectNode(ele);window.getSelection().addRange(range);document.execCommand('copy');window.getSelection().removeAllRanges()}else{ele.focus();ele.select();document.execCommand('copy')}}};suoIm.show()})();" title="点击运行">短网址</a></li><li>安装: 将上一行的 <code>短网址</code> 拖入到书签栏即可</li></ul><!-- 引用javascript:1.不能有双引号(换成单引号)2 压缩 https://c.runoob.com/front-end/513 空格换为%20--><h2 id="IOS捷径"><a href="#IOS捷径" class="headerlink" title="IOS捷径"></a>IOS捷径</h2><p>地址: <a href="https://www.icloud.com/shortcuts/3f4de7b4f2a1415b8cd34eec19874b27">https://www.icloud.com/shortcuts/3f4de7b4f2a1415b8cd34eec19874b27</a></p><p><img src="https://7.dusays.com/2021/05/05/80cb08a7623be.png" alt="扫码在safari浏览器中打开安装"></p><h2 id="更多功能"><a href="#更多功能" class="headerlink" title="更多功能"></a>更多功能</h2><div class='checkbox green checked'><input type="checkbox" checked="checked"/> <p>密码短网址</p> </div><div class='checkbox green checked'><input type="checkbox" checked="checked"/> <p>匿名网址</p> </div><div class='checkbox green checked'><input type="checkbox" checked="checked"/> <p>统计分析</p> </div><blockquote><p>请访问官网: <a href="https://suowo.cn/">https://suowo.cn/</a></p></blockquote><!-- <script src="/js/suo.im.js"></script> -->]]></content>
<summary type="html"><p>基于 <del><a href="https://suowo.cn/">suowo.cn</a></del>(开始弹广告了…) 官方API制作的 <code>短网址生成</code> 的小书签和快捷指令</p>
<p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/991130e/xiaoshuqian.png" alt="小书签版运行截图"></p></summary>
<category term="IT技术" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/"/>
<category term="JavaScript" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/JavaScript/"/>
<category term="短网址生成" scheme="https://7bxing.com/tags/%E7%9F%AD%E7%BD%91%E5%9D%80%E7%94%9F%E6%88%90/"/>
</entry>
<entry>
<title>VIDAA3/4系统工厂模式</title>
<link href="https://7bxing.com/posts/be2c6b79/"/>
<id>https://7bxing.com/posts/be2c6b79/</id>
<published>2020-07-05T14:06:01.000Z</published>
<updated>2020-07-05T14:06:01.000Z</updated>
<content type="html"><![CDATA[<p>之前(海信电视)在安装当贝市场时 了解到 <a href="https://baike.baidu.com/item/%E6%B5%B7%E4%BF%A1VIDAA/1963115?fr=aladdin" title="VIDAA:海信电视的操作系统">VIDAA</a> 系统,但在网上查找了各种方法,没能进入工厂模式<br>最近无意中看到方法(准确说应该是网上终于更新了),特此记录!</p><p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/be2c6b79/factory-mode.png" alt="工厂模式"></p><span id="more"></span><blockquote><p>不同电视品牌、型号进入工厂模式的方法都不一样…<br>好好的开发功能,做优化,不好么? 搞这些!!!</p></blockquote><h2 id="进入工厂模式"><a href="#进入工厂模式" class="headerlink" title="进入工厂模式"></a>进入工厂模式</h2><ol><li>按遥控器上的「智汇」键,进入到桌面</li><li>点击「设置」项进入设置界面</li><li>点击「声音设置」,遥控器选中「声音平衡」</li><li>依次按遥控器「菜单 - OK - 菜单 - OK」键</li><li>此时可以看到电视机左上角出现大字「M」</li><li>接着按遥控器上的「菜单」键</li><li>进入到工程设置界面(普通用户请谨慎操作)</li></ol><blockquote><p>退出方法: 遥控器关机,再开机 然后选择电视信号源</p></blockquote><h2 id="相关参数"><a href="#相关参数" class="headerlink" title="相关参数"></a>相关参数</h2><p>开机模式,三种选项的含义是:</p><ul><li>记忆 - 关闭机身电源开关,再次打开时,电视状态为关闭前的状态,物理关机前用遥控器关了就是关,没关就是开</li><li>关 - 关闭机身电源开关,再次打开时,电视状态永远为关,需要按一下遥控器的电源才会打开</li><li>开 - 关闭机身电源开关,再次打开时,电视状态永远为开</li></ul><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>如果需要关闭开机广告,直接打客服电话反馈就行,不用自己去破解</p><h2 id="参考教程"><a href="#参考教程" class="headerlink" title="参考教程"></a>参考教程</h2><p><a href="https://www.znds.com/tv-1170617-1-1.html">海信电视精简教程,去除电视多余应用,换桌面</a></p><p><a href="https://www.znds.com/tv-1010861-1-1.html">海信工厂模式没有adb调试的开启方法</a></p>]]></content>
<summary type="html"><p>之前(海信电视)在安装当贝市场时 了解到 <a href="https://baike.baidu.com/item/%E6%B5%B7%E4%BF%A1VIDAA/1963115?fr=aladdin" title="VIDAA:海信电视的操作系统">VIDAA</a> 系统,但在网上查找了各种方法,没能进入工厂模式<br>最近无意中看到方法(准确说应该是网上终于更新了),特此记录!</p>
<p><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/md/be2c6b79/factory-mode.png" alt="工厂模式"></p></summary>
<category term="未分类" scheme="https://7bxing.com/categories/%E6%9C%AA%E5%88%86%E7%B1%BB/"/>
<category term="VIDAA系统" scheme="https://7bxing.com/tags/VIDAA%E7%B3%BB%E7%BB%9F/"/>
</entry>
<entry>
<title>Shell猜数字游戏</title>
<link href="https://7bxing.com/posts/3713cf69/"/>
<id>https://7bxing.com/posts/3713cf69/</id>
<published>2020-06-06T13:12:21.000Z</published>
<updated>2020-06-08T13:12:21.000Z</updated>
<content type="html"><![CDATA[<p>猜数字游戏加强版, 熟悉shell的基础语法,shell注意事项</p><span id="more"></span><h3 id="猜数字规则"><a href="#猜数字规则" class="headerlink" title="猜数字规则"></a>猜数字规则</h3><ul><li>随机生成一个0~99的数字</li><li>输入错误 直接返回重新输入</li><li>猜测错误 提示大小 继续猜测(并返回剩余猜测次数)</li><li>连续猜错5次 退出(提示GAME OVER)</li><li>猜测正确(返回 you got it!)</li></ul><h3 id="Shell备忘"><a href="#Shell备忘" class="headerlink" title="Shell备忘"></a>Shell备忘</h3><h4 id="1-文件模式"><a href="#1-文件模式" class="headerlink" title="1. 文件模式"></a>1. 文件模式</h4><p>windows下的换行(\r\n)与linux(\n)下不同,如果是windows下创建的shell文件,传到linux后,需要在vim下重设格式为linux模式(重新编辑不需要改)</p><ul><li><code>set ff</code> 查看文件模式</li><li><code>set ff=unix</code> 设置文件为unix模式<blockquote><p>注:mac系统换行为(\r)</p></blockquote></li></ul><h4 id="2-立即执行"><a href="#2-立即执行" class="headerlink" title="2. 立即执行"></a>2. 立即执行</h4><ul><li>$()</li><li>``<blockquote><p>推荐最外层用反引号``,内层用$()<br>rn=$((`head -20 /dev/urandom | cksum | cut -f1 -d “ “` % 100))<br>$(()) 表示算数运算</p></blockquote></li></ul><h4 id="3-各种判断"><a href="#3-各种判断" class="headerlink" title="3. 各种判断"></a>3. 各种判断</h4><p>推荐用法:</p><ul><li><code>[]</code> 用于判断文件(目录)或者变量的存在与否,如 [ -z “a.sh” ] </li><li><code>[[]]</code> 用于正则判断,如 [[ “$INT” =~ ^-?[0-9]+$ ]]</li><li><code>(())</code> 用于整数比较和计算,如 (( $gn > $rn )) 、$((chance-count))</li><li>!表示否定,如 [ ! -z “a.sh” ]</li><li>测试: ((1>2)) && echo 111 || echo 222<blockquote><p>注: <code>[]</code> 和 <code>[[]]</code> 两边必须有空格</p></blockquote></li></ul><h4 id="4-函数的返回值"><a href="#4-函数的返回值" class="headerlink" title="4. 函数的返回值"></a>4. <a href="https://www.runoob.com/linux/linux-shell-func.html">函数</a>的返回值</h4><ul><li>可以显示加:return 返回</li><li>如果不加,将以最后一条命令运行结果,作为返回值</li><li>return后跟数值n(0-255)<blockquote><p>如需要其他返回值: 可以通过echo返回字符串,或者操作全局变量</p></blockquote></li></ul><h3 id="远程执行"><a href="#远程执行" class="headerlink" title="远程执行"></a>远程执行</h3><p>拷贝下列命令,在 linux 环境下粘贴执行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bash <(curl -sSL https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/demo/guess.sh)</span><br></pre></td></tr></table></figure><h3 id="猜数字代码"><a href="#猜数字代码" class="headerlink" title="猜数字代码"></a>猜数字代码</h3><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"><span class="comment"># Shell猜数字游戏</span></span><br><span class="line"><span class="comment"># 规则</span></span><br><span class="line"><span class="comment"># 1 随机生成一个0~99的数字</span></span><br><span class="line"><span class="comment"># 2 输入错误 直接返回重新输入</span></span><br><span class="line"><span class="comment"># 3 猜测错误 提示大小 继续猜测(并返回剩余猜测次数)</span></span><br><span class="line"><span class="comment"># 4 连续猜错5次 退出(提示GAME OVER)</span></span><br><span class="line"><span class="comment"># 5 猜测正确(返回 you got it!)</span></span><br><span class="line"></span><br><span class="line">count=0</span><br><span class="line">chance=5</span><br><span class="line"></span><br><span class="line"><span class="built_in">cat</span> << <span class="string">EOF</span></span><br><span class="line"><span class="string">======= Shell猜数字游戏 =======</span></span><br><span class="line"><span class="string"># 数字区间[0~99]</span></span><br><span class="line"><span class="string"># 你共有${chance}次机会!</span></span><br><span class="line"><span class="string"># Ctrl+C可强制退出</span></span><br><span class="line"><span class="string">EOF</span></span><br><span class="line"></span><br><span class="line">rn=$((`head -<span class="number">20</span> /dev/urandom | cksum | cut -f1 -d " "` % <span class="number">100</span>))</span><br><span class="line"><span class="comment"># echo $rn</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">echoColor</span></span>(){</span><br><span class="line"> <span class="built_in">declare</span> -A colors</span><br><span class="line"> colors=(</span><br><span class="line"> [black]=30 <span class="comment"># 30m 黑色字</span></span><br><span class="line"> [red]=31 <span class="comment"># 31m 红色字</span></span><br><span class="line"> [green]=32 <span class="comment"># 32m 绿色字</span></span><br><span class="line"> [yellow]=33 <span class="comment"># 33m 黄色字</span></span><br><span class="line"> [blue]=34 <span class="comment"># 34m 蓝色字</span></span><br><span class="line"> [purple]=35 <span class="comment"># 35m 紫色字</span></span><br><span class="line"> [skyblue]=36 <span class="comment"># 36m 天蓝字</span></span><br><span class="line"> [white]=37 <span class="comment"># 37m 白色字</span></span><br><span class="line"> )</span><br><span class="line"> mes=<span class="string">"<span class="variable">$1</span>"</span></span><br><span class="line"> <span class="comment"># 示例 echo -e "\033[31m 颜色字 \033[0m"</span></span><br><span class="line"> <span class="built_in">echo</span> -e <span class="string">"\033[<span class="variable">${colors[$2]}</span>m<span class="variable">${mes}</span>\033[0m"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">chkValue</span></span>(){</span><br><span class="line"> gn=<span class="string">"<span class="variable">$1</span>"</span></span><br><span class="line"> <span class="comment"># 非空判断</span></span><br><span class="line"> <span class="keyword">if</span> [ -z <span class="string">"<span class="variable">$gn</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> echoColor <span class="string">"你还未输入呢"</span> <span class="string">"skyblue"</span></span><br><span class="line"> <span class="built_in">continue</span></span><br><span class="line"> <span class="comment"># 有效数字判断</span></span><br><span class="line"> <span class="keyword">elif</span> <span class="built_in">echo</span> <span class="string">"<span class="variable">$gn</span>"</span> | grep -q <span class="string">'[^0-9]'</span>; <span class="keyword">then</span></span><br><span class="line"> echoColor <span class="string">"请输入有效的数字"</span> <span class="string">"red"</span></span><br><span class="line"> <span class="built_in">continue</span></span><br><span class="line"> <span class="comment"># 范围判断</span></span><br><span class="line"> <span class="keyword">elif</span> (( <span class="variable">$gn</span> < <span class="number">0</span> )) || (( <span class="variable">$gn</span> > <span class="number">99</span> )); <span class="keyword">then</span></span><br><span class="line"> echoColor <span class="string">"输入大小有误,请重新输入!"</span> <span class="string">"red"</span></span><br><span class="line"> <span class="built_in">continue</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">chkCount</span></span>(){</span><br><span class="line"> <span class="keyword">if</span> (( <span class="variable">$1</span> >= <span class="variable">$chance</span> )); <span class="keyword">then</span></span><br><span class="line"> echoColor <span class="string">"<span class="variable">${chance}</span>次机会已用完, GAME OVER!"</span> <span class="string">"blue"</span></span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="title">guess</span></span>(){</span><br><span class="line"> <span class="keyword">while</span> <span class="literal">true</span>; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">read</span> -p <span class="string">"请输入你猜测的数字[0~99]:"</span> gn</span><br><span class="line"> chkValue <span class="string">"<span class="variable">$gn</span>"</span></span><br><span class="line"> <span class="built_in">break</span></span><br><span class="line"> <span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (( <span class="variable">$gn</span> > <span class="variable">$rn</span> )); <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">let</span> <span class="string">"count++"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">'猜大了'</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"剩余猜测次数:<span class="subst">$((chance-count)</span>)"</span></span><br><span class="line"> chkCount <span class="variable">$count</span></span><br><span class="line"> guess</span><br><span class="line"> <span class="keyword">elif</span> (( <span class="variable">$gn</span> < <span class="variable">$rn</span> )); <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">let</span> <span class="string">"count++"</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">'猜小了'</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"剩余猜测次数:<span class="subst">$((chance-count)</span>)"</span></span><br><span class="line"> chkCount <span class="variable">$count</span></span><br><span class="line"> guess</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> echoColor <span class="string">"you got it!!!"</span> <span class="string">"green"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">guess</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>猜数字游戏加强版, 熟悉shell的基础语法,shell注意事项</p></summary>
<category term="IT技术" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/"/>
<category term="Shell" scheme="https://7bxing.com/categories/IT%E6%8A%80%E6%9C%AF/Shell/"/>
<category term="Shell" scheme="https://7bxing.com/tags/Shell/"/>
<category term="猜数字游戏" scheme="https://7bxing.com/tags/%E7%8C%9C%E6%95%B0%E5%AD%97%E6%B8%B8%E6%88%8F/"/>
</entry>
<entry>
<title>Git学习</title>
<link href="https://7bxing.com/posts/e28ceec1/"/>
<id>https://7bxing.com/posts/e28ceec1/</id>
<published>2020-05-16T05:05:02.000Z</published>
<updated>2020-05-16T05:05:02.000Z</updated>
<content type="html"><![CDATA[<p>快速学习Git, Git学习总结, 常见问题 </p><span id="more"></span><h2 id="本文用于快速学习git"><a href="#本文用于快速学习git" class="headerlink" title="本文用于快速学习git"></a>本文用于快速学习git</h2><p><del>请使用 <code>Chrome</code> 浏览器, 并安装 <code>MarkDown Preview Plus</code> 扩展后查看本文档</del></p><h2 id="三年-Git-使用心得-amp-常见问题整理"><a href="#三年-Git-使用心得-amp-常见问题整理" class="headerlink" title="三年 Git 使用心得 & 常见问题整理"></a>三年 Git 使用心得 & 常见问题整理</h2><p><a href="https://juejin.im/post/5ee649ff51882542ea2b5108">https://juejin.im/post/5ee649ff51882542ea2b5108</a></p><h2 id="廖雪峰教程"><a href="#廖雪峰教程" class="headerlink" title="廖雪峰教程"></a>廖雪峰教程</h2><ul><li><a href="https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000">教程链接</a></li><li><a href="https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/001375234012342f90be1fc4d81446c967bbdc19e7c03d3000">别名配置</a></li><li>别名记录<figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">$ git config --global alias.st status</span><br><span class="line"> st -> status</span><br><span class="line"> co -> checkout</span><br><span class="line"> ci -> commit</span><br><span class="line"> br -> branch</span><br><span class="line"> unstage -> reset HEAD</span><br><span class="line"> last -> log -1</span><br><span class="line"> lg -> log --color --graph --pretty=format:'...' --abbrev-commit</span><br></pre></td></tr></table></figure></li></ul><h2 id="服务端"><a href="#服务端" class="headerlink" title="服务端"></a>服务端</h2><ul><li><a href="https://gogs.io/">Gogs</a></li></ul><h2 id="推荐客户端(smartgit)"><a href="#推荐客户端(smartgit)" class="headerlink" title="推荐客户端(smartgit)"></a>推荐客户端(smartgit)</h2><ul><li><a href="https://www.syntevo.com/smartgit/download/">Download</a></li></ul><h2 id="git-bash命令"><a href="#git-bash命令" class="headerlink" title="git-bash命令"></a>git-bash命令</h2><ul><li>命令图解<br><img src="https://gcore.jsdelivr.net/gh/qinxs/cdn-assets@master/img/git1.jpg" alt="git命令图解"></li><li><a href="https://blog.csdn.net/qq_20282263/article/details/80859589">常用命令</a></li><li><a href="https://www.cnblogs.com/SamWeb/p/6516784.html">文件夹操作</a></li><li><a href="https://blog.csdn.net/zly9923218/article/details/53405156">常用快捷键</a></li><li>快捷键<figure class="highlight plaintext"><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">Ctrl + A 移动光标到整条命令的起始位置</span><br><span class="line">Ctrl + E 移动光标到整条命令的结束位置</span><br><span class="line">Ctrl + ← 移动光标到单词的左边</span><br><span class="line">Ctrl + → 移动光标到单词的右边</span><br><span class="line">Ctrl + U 删除光标左侧的所有内容</span><br><span class="line">Ctrl + K 删除光标右侧的所有内容</span><br><span class="line">Ctrl + L 清屏(与reset类似,但不清除已显示内容)</span><br><span class="line">移动命令 上(上一行)、下(下一行)、F(下一页)、B(上一页)、D(下半页)、U(上半页)、q(退出)</span><br><span class="line">其 他: Tab、上下</span><br></pre></td></tr></table></figure></li></ul>]]></content>
<summary type="html"><p>快速学习Git, Git学习总结, 常见问题 </p></summary>
<category term="工具学习" scheme="https://7bxing.com/categories/%E5%B7%A5%E5%85%B7%E5%AD%A6%E4%B9%A0/"/>
<category term="Git" scheme="https://7bxing.com/categories/%E5%B7%A5%E5%85%B7%E5%AD%A6%E4%B9%A0/Git/"/>
<category term="Git" scheme="https://7bxing.com/tags/Git/"/>
</entry>
<entry>
<title>hello world</title>
<link href="https://7bxing.com/posts/d4a1185/"/>
<id>https://7bxing.com/posts/d4a1185/</id>
<published>2020-05-16T05:00:02.000Z</published>
<updated>2020-05-16T05:00:02.000Z</updated>
<content type="html"><![CDATA[<p>Hexo自动生成的hello world</p><span id="more"></span><p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content>
<summary type="html"><p>Hexo自动生成的hello world</p></summary>
<category term="未分类" scheme="https://7bxing.com/categories/%E6%9C%AA%E5%88%86%E7%B1%BB/"/>
<category term="其他" scheme="https://7bxing.com/tags/%E5%85%B6%E4%BB%96/"/>
</entry>
</feed>