-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathatom.xml
More file actions
530 lines (302 loc) · 144 KB
/
atom.xml
File metadata and controls
530 lines (302 loc) · 144 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
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>xtutu</title>
<subtitle>学习|思考|分享</subtitle>
<link href="http://xtutu.github.io/atom.xml" rel="self"/>
<link href="http://xtutu.github.io/"/>
<updated>2023-05-24T08:46:04.936Z</updated>
<id>http://xtutu.github.io/</id>
<author>
<name>xtutu</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>「宇宙点状文明」模拟程序</title>
<link href="http://xtutu.github.io/universe-civilization-simulation/"/>
<id>http://xtutu.github.io/universe-civilization-simulation/</id>
<published>2017-02-17T13:00:00.000Z</published>
<updated>2023-05-24T08:46:04.936Z</updated>
<content type="html"><![CDATA[<p><img src="/img/simluation/3.jpg"></p><hr><p>引自《三体》后记:</p><blockquote><p>我曾经陷入【宇宙文明点状化】的这种思维游戏中不可自拔<br>那个时期,我还编过一个宇宙点状文明体系总体状态的模拟软件,将宇宙间的智慧文明简化为点,每个点只具有描述该文明基本特征的十几个简单参数,然后将文明的数量设置得十分巨大,在软件中模拟这个体系的整体演化过程。<br>软件运行时最多的一次曾在十万光年半径内设定了三十万个文明,这个用现在看来很简陋的TUBOC编的程序在286机上运行了几个小时,结果很有趣。</p></blockquote><p>模拟地址:<a href="http://xtutu.github.io/simulation">simulation</a><br>知乎回答:<a href="https://www.zhihu.com/question/21296837/answer/146050873">知乎地址</a></p><span id="more"></span><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p><img src="/img/simluation/3.jpg"></p>
<hr>
<p>引自《三体》后记:</p>
<blockquote>
<p>我曾经陷入【宇宙文明点状化】的这种思维游戏中不可自拔<br>那个时期,我还编过一个宇宙点状文明体系总体状态的模拟软件,将宇宙间的智慧文明简化为点,每个点只具有描述该文明基本特征的十几个简单参数,然后将文明的数量设置得十分巨大,在软件中模拟这个体系的整体演化过程。<br>软件运行时最多的一次曾在十万光年半径内设定了三十万个文明,这个用现在看来很简陋的TUBOC编的程序在286机上运行了几个小时,结果很有趣。</p>
</blockquote>
<p>模拟地址:<a href="http://xtutu.github.io/simulation">simulation</a><br>知乎回答:<a href="https://www.zhihu.com/question/21296837/answer/146050873">知乎地址</a></p></summary>
<category term="模拟" scheme="http://xtutu.github.io/categories/%E6%A8%A1%E6%8B%9F/"/>
<category term="点状宇宙文明" scheme="http://xtutu.github.io/tags/%E7%82%B9%E7%8A%B6%E5%AE%87%E5%AE%99%E6%96%87%E6%98%8E/"/>
</entry>
<entry>
<title> VR项目-Demo完结</title>
<link href="http://xtutu.github.io/vr-project-demo/"/>
<id>http://xtutu.github.io/vr-project-demo/</id>
<published>2017-02-17T12:00:00.000Z</published>
<updated>2023-05-24T08:46:04.936Z</updated>
<content type="html"><![CDATA[<p>之前一段时间做了一个VR项目的Demo。一款p2p的竞技类游戏,玩法类似皇室战争。<br>现在已经结束了,放一些图片和视频作为记录。<br><img src="/img/vr/0.png"></p><hr><span id="more"></span><h2 id="视频"><a href="#视频" class="headerlink" title="视频"></a>视频</h2><video src='/img/video/vr-demo.mp4' type='video/mp4' controls='controls' width='100%' height='100%'></video><hr><h2 id="图片"><a href="#图片" class="headerlink" title="图片"></a>图片</h2><p><img src="/img/vr/1.png"><br><img src="/img/vr/2.png"><br><img src="/img/vr/3.png"><br><img src="/img/vr/4.png"><br><img src="/img/vr/5.png"><br><img src="/img/vr/6.png"><br><img src="/img/vr/10.png"></p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p>之前一段时间做了一个VR项目的Demo。一款p2p的竞技类游戏,玩法类似皇室战争。<br>现在已经结束了,放一些图片和视频作为记录。<br><img src="/img/vr/0.png"></p>
<hr></summary>
<category term="Demo" scheme="http://xtutu.github.io/categories/Demo/"/>
<category term="VR" scheme="http://xtutu.github.io/tags/VR/"/>
</entry>
<entry>
<title>Git submodule & pull request ! 让我们啃下这块骨头!</title>
<link href="http://xtutu.github.io/git-submodule-and-pull-request/"/>
<id>http://xtutu.github.io/git-submodule-and-pull-request/</id>
<published>2016-12-03T00:30:00.000Z</published>
<updated>2023-05-24T08:46:04.932Z</updated>
<content type="html"><![CDATA[<p>实际上submodule 与 pull request,并没有什么直接关系。<br>比如一些团队采用code-review的方式进行协作,那么他们可能只用到pull request。<br>这里之所以放在一起,是因为很多场景用到了其中一个,就少不了另一个。<br><strong>那么,什么情况下我们需要用到 submodule 和 pull request呢?!</strong></p><hr><p>假设我们的项目是用git来管理,这时我们需要添加一个第三方库的源码(以下简称lib),而这个lib,也是通过git来管理。<br>这种情况,一般有两种选择:</p><ol><li><strong>把lib的源码复制到我们的项目中,把它作为当前项目的源码进行管理。</strong></li><li><strong>通过git clone的方式,把lib整个放到我们的项目中(保留它自身的git信息),作为git的submodule。</strong></li></ol><p>这两种方式各有利弊,接下去就来好好分析一下。</p><span id="more"></span><hr><h2 id="方式1—只复制源码"><a href="#方式1—只复制源码" class="headerlink" title="方式1—只复制源码"></a>方式1—只复制源码</h2><p>第一种方式对于项目自身的管理来说,非常简单,没有引入额外的概念。<br>如果我们需要修改第三方库的功能,直接改就可以了。<br><strong>但这种方式在以下几种情况,会显得非常糟糕:</strong></p><ol><li><p><strong>更新lib的源码到最新版本</strong><br>如果我们已经在自己的项目仓库对这lib进行了很多修改。<br>然后某一天,lib的官方github发布了许多非常有用的更新,那这时候的合并工作,就必须得借助第三方工具。</p></li><li><p><strong>为lib贡献自己的代码</strong><br>当我们在使用lib时,发现了一个bug,并解决了。我们很难把修复这个bug的commit,告诉官方的github。<br><em>有悖开源的目的。</em></p></li></ol><p><strong>所以接下去,本文将着重介绍方法2的操作方式!!!</strong></p><hr><h2 id="方式2—submodule-amp-pull-request"><a href="#方式2—submodule-amp-pull-request" class="headerlink" title="方式2—submodule & pull request"></a>方式2—submodule & pull request</h2><p>方式1中遇到的问题,通过采用 submodule 就可以很好的解决,但是submodule本身特别绕。<br>所以本文将以我的博客仓库作为案例来分析。</p><h3 id="背景介绍"><a href="#背景介绍" class="headerlink" title="背景介绍"></a>背景介绍</h3><p><strong>博客主题是一个独立的模块,所以我有以下两个仓库,theme作为blog的submodule来管理。</strong></p><ol><li>我的博客仓库为 xtutu/blog.git</li><li>博客的主题仓库 xtutu/theme.git ===> fork from official/theme.git</li></ol><p><em>这里可以看到xtutu/theme.git 是一个从官方仓库 fork出来的分支!</em><br><em>xtutu/blog.git储存在我们自己的git仓库里.(所以仓库的前缀是xtutu/)。</em></p><p><strong>如果你对submodule、pull request 都有一定了解,可以直接看2.4的小结内容!!!</strong><br><strong>那里有我目前的操作流程!</strong></p><hr><h3 id="submodule-部分"><a href="#submodule-部分" class="headerlink" title="submodule 部分"></a>submodule 部分</h3><h4 id="添加-submodule"><a href="#添加-submodule" class="headerlink" title="添加 submodule"></a>添加 submodule</h4><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># clone blog仓库到本地</span></span><br><span class="line">$ git <span class="built_in">clone</span> xxxxxxx/blog.git</span><br><span class="line">$ <span class="built_in">cd</span> blog</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在blog仓库下,执行下面这个语句,就会创建一个themes文件夹下,创建一个名为theme的submodule</span></span><br><span class="line">$ git submodule add git@github.com:xtutu/theme.git themes/theme</span><br><span class="line"></span><br><span class="line"><span class="comment"># 看看blog当前的状态</span></span><br><span class="line">$ git status</span><br><span class="line">On branch master</span><br><span class="line">Your branch is up-to-date with <span class="string">'origin/master'</span>.</span><br><span class="line">Changes to be committed:</span><br><span class="line"> (use <span class="string">"git reset HEAD <file>..."</span> to unstage)</span><br><span class="line"></span><br><span class="line"> new file: .gitmodules</span><br><span class="line"> new file: themes/theme</span><br><span class="line"></span><br><span class="line"><span class="comment"># 提交所有记录</span></span><br><span class="line">$ git commit -am <span class="string">"add submodule theme"</span></span><br><span class="line">$ git push <span class="comment"># 执行完这句命令之后 submodule 就添加完成了</span></span><br></pre></td></tr></table></figure><p><strong>注意!!!</strong><br><strong>blog仓库中的 theme 文件夹下面的内容并没有提交到blog仓库,而是只提交了一个空的theme目录。</strong><br><strong>可以理解为:在blog.git中,只记录了submodule的状态,而不是实际内容!</strong></p><p><img src="/img/git/1.jpg"><br><em>从图中可以看到,blog仓库会记录submodule,对应在theme仓库中的commit id</em></p><hr><h4 id="对submodule进行git操作"><a href="#对submodule进行git操作" class="headerlink" title="对submodule进行git操作"></a>对submodule进行git操作</h4><figure class="highlight bash"><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 class="comment"># Administrator at USER-20160613SI in /f/blog on git:master o [14:18:52]</span></span><br><span class="line">$ <span class="built_in">cd</span> themes/theme</span><br></pre></td></tr></table></figure><p>切换到theme下面之后,执行的各种git操作(包括cmmit、push等),都是只针对 xtutu/theme.git进行的。<br>这与普通的git操作并没有什么不同。</p><p><strong>但需要这注意的是:</strong>对theme.git执行了修改操作之后,blog.git会察觉到theme文件夹的commit id发生了变化!<br><strong>所以需要在blog仓库中,进行一次常规的commit,用于提交 submodule 状态修改!</strong></p><hr><h4 id="同步一个包含submodule的仓库"><a href="#同步一个包含submodule的仓库" class="headerlink" title="同步一个包含submodule的仓库"></a>同步一个包含submodule的仓库</h4><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><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">$ git clone xxxxxxx/blog.git blog2</span><br><span class="line">$ cd blog2</span><br><span class="line"># 执行完上面这部分之后,虽然创建了themes/theme文件夹,但文件夹里并没有内容...</span><br><span class="line"># 所以我们还需要以下操作:</span><br><span class="line"></span><br><span class="line"># 第一次clone需要进行注册。</span><br><span class="line">$ git submodule init</span><br><span class="line"></span><br><span class="line"># 进行更新</span><br><span class="line">$ git submodule update</span><br><span class="line">### 到这为止,theme下面已经有了具体的内容!</span><br><span class="line">---------------------------------------------</span><br><span class="line"># 以上3条 git 命令,也可以用这句话代替</span><br><span class="line">$ git clone xtutu/blog.git blog2 --recursive</span><br></pre></td></tr></table></figure><p><strong>注意!!!</strong><br><strong>默认clone下来的submodule不属于任何branch,处于游离状态,所以一定要记得执行下面的操作!</strong></p><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># Administrator at USER-20160613SI in /f/blog2 on git:master o [14:45:37]</span></span><br><span class="line">$ <span class="built_in">cd</span> themes/theme</span><br><span class="line"></span><br><span class="line"><span class="comment"># Administrator at USER-20160613SI in /f/blog2/themes/theme on git:966eb5d o [14:52:23]</span></span><br><span class="line">$ git branch</span><br><span class="line">* (detached from 966eb5d)</span><br><span class="line"> master</span><br><span class="line"></span><br><span class="line"><span class="comment"># Administrator at USER-20160613SI in /f/blog2/themes/theme on git:966eb5d o [14:52:52]</span></span><br><span class="line">$ git checkout master</span><br><span class="line">Switched to branch <span class="string">'master'</span></span><br><span class="line">Your branch is up-to-date with <span class="string">'origin/master'</span>.</span><br><span class="line"></span><br><span class="line"><span class="comment"># Administrator at USER-20160613SI in /f/blog2/themes/theme on git:master o [14:54:42]</span></span><br><span class="line">$</span><br></pre></td></tr></table></figure><p>当最后一条命令执行完毕之后,可以在命令行上看到。我们已经进入到了master分支!</p><hr><h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><p>了解了上面这些内容之后,使用submodule应没什么太大问题了。<br>但是方式1提到的两个问题,还是没有涉及到!<br><strong>接下去的内容就是来解决这两个问题。</strong></p><hr><h3 id="pull-request-部分"><a href="#pull-request-部分" class="headerlink" title="pull request 部分"></a>pull request 部分</h3><h4 id="pull-request-大致浏览"><a href="#pull-request-大致浏览" class="headerlink" title="pull request 大致浏览"></a>pull request 大致浏览</h4><p>下面的内容,实际上和submodule已经没有任何关系。<br>pull request & update 等操作,都是针对于 xutut/theme.git 以及 official/theme.git (原始的官方仓库)。</p><ol><li>进入xtutu/theme.git主页,如图所示<br><img src="/img/git/2.jpg"></li><li>点击pull request<br><img src="/img/git/3.jpg"><br>从图中可以看到,当我们点击Create pull request之后,就会把自己仓库的修改提交到official/theme.git。<br><em>准确的说:应该是发起一个提交的请求。最后由官方仓库的拥有者,觉得是否接受提交。</em></li></ol><p><strong>但是在这个页面会列出所有的修改,包括不是用于修复这个bug的commit!</strong><br>所以如果我们只是想pull request一个(或者几个)修复bug的commit,而不是所有的commit。那该怎么做呢?!<br><em>我在搜索资料的时候大致看了下,用cherry-pick命令应该可以完成这一效果。不过这里不采用这种方式</em></p><h4 id="pull-request的正确姿势"><a href="#pull-request的正确姿势" class="headerlink" title="pull request的正确姿势"></a>pull request的正确姿势</h4><p><strong>在自己的仓库中,新建一个专门用于修复这个bug的branch。</strong><br>当这个bug修复了之后,我们再通过网页,在这个branch上 pull request!<br>这样pull request里面的commit全都是为了修复这个bug而提交的。</p><p>当然了,不管最后官方仓库,要不要接受这个pull request。<br>我们自己使用的xtutu/theme.git master分支,都可以把这个修复bug的分支合并过来!(就是普通的merge操作,相信大家都已经很熟悉了)</p><p><strong>注意事项</strong><br>我们用于pull request的的分支,最好更新到official/theme.git的最新状态,<strong>并保持HEAD一致(git rebase & reset命令)!</strong>再进行提交!<br>下面就讲一讲如何从official/theme.git 拉取最新的状态。</p><h4 id="同步官方仓库的最新修改"><a href="#同步官方仓库的最新修改" class="headerlink" title="同步官方仓库的最新修改"></a>同步官方仓库的最新修改</h4><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 添加一个新的远程仓库</span></span><br><span class="line">$ git remote add upstream https://github.com/...../official/theme.git</span><br><span class="line"></span><br><span class="line"><span class="comment"># Administrator at USER-20160613SI in /f/mygit/blog/themes/next on git:master o [16:07:26]</span></span><br><span class="line">$ git remote -v</span><br><span class="line">origin git@github.com:xtutu/theme.git (fetch)</span><br><span class="line">origin git@github.com:xtutu/theme.git (push)</span><br><span class="line">upstream https://github.com/xxxxxxx/theme.git (fetch)</span><br><span class="line">upstream https://github.com/xxxxxxx/theme.git (push)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 设置从upstream上拉取数据</span></span><br><span class="line">$ git pull upstream master</span><br><span class="line"><span class="comment"># 推送到自己的 xutut/theme.git 仓库中</span></span><br><span class="line">$ git push</span><br></pre></td></tr></table></figure><p>这里做的就是普通的merge操作,不同之处在于是从一个新的remote上进行merge。</p><h3 id="小结-1"><a href="#小结-1" class="headerlink" title="小结"></a>小结</h3><p>我目前的做法是在xtutu/theme.git中,一直保存着2个分支。</p><ol><li><p>master:针对自己的需求,进行的所有修改,都会提交到这里<br>比如在现有主题上,更改显示效果,添加自己的信息等。</p></li><li><p>latest-from-upstream: 永远与官方的master保持一致!<br>该分支主要用于<strong>创建</strong> <em>执行pull request操作的</em> <strong>分支</strong>,该分支要保持干净。<br>(<strong>注意:该分支不是为了创建pull reqeust,而是为了创建(执行pull request操作的)分支</strong>)<br>保持干净是为了:在pull request时,避免出现不相干的commit id。</p></li></ol><p><strong>当需要提交一个新的pull request时,可以执行以下操作。</strong></p><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></pre></td><td class="code"><pre><span class="line">$ git checkout latest-from-upstream</span><br><span class="line">$ git pull upstream master <span class="comment"># 同步官方仓库的更新</span></span><br><span class="line">$ git checkout -b new-feature <span class="comment"># 创建用于pull request的分支</span></span><br><span class="line"><span class="comment"># 然后进行各种修改。</span></span><br><span class="line">$ git ......</span><br><span class="line"><span class="comment"># 推到xtutu/theme.git上</span></span><br><span class="line">$ git push origin new-feature</span><br><span class="line"></span><br><span class="line"><span class="comment"># 最后通过网页,进行pull request操作。</span></span><br><span class="line"><span class="comment"># 如果我们自己也需要用这个修改,只需要从本地的master分支,merge这个new-feature分支。</span></span><br></pre></td></tr></table></figure><h2 id="最后的最后"><a href="#最后的最后" class="headerlink" title="最后的最后"></a>最后的最后</h2><p>写了这么多,大家在用的时候肯定还会遇到不少问题。不过了解了上面这些知识点,再去搜索下,应该可以比较容易的解决。<br>上面的操作流程,也只是我自己摸索出来的方式,如果有更好的建议,可以给我留言,大家一起讨论。</p><p><strong>最后,附上一张截图:这是我采用这种方式,给<a href="https://github.com/iissnan/hexo-theme-next">hexo-theme-next</a>提的一个pull request。</strong><br>哈哈哈,成功merge!<br><img src="/img/git/5.jpg"></p><hr><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p>实际上submodule 与 pull request,并没有什么直接关系。<br>比如一些团队采用code-review的方式进行协作,那么他们可能只用到pull request。<br>这里之所以放在一起,是因为很多场景用到了其中一个,就少不了另一个。<br><strong>那么,什么情况下我们需要用到 submodule 和 pull request呢?!</strong></p>
<hr>
<p>假设我们的项目是用git来管理,这时我们需要添加一个第三方库的源码(以下简称lib),而这个lib,也是通过git来管理。<br>这种情况,一般有两种选择:</p>
<ol>
<li><strong>把lib的源码复制到我们的项目中,把它作为当前项目的源码进行管理。</strong></li>
<li><strong>通过git clone的方式,把lib整个放到我们的项目中(保留它自身的git信息),作为git的submodule。</strong></li>
</ol>
<p>这两种方式各有利弊,接下去就来好好分析一下。</p></summary>
<category term="长知识" scheme="http://xtutu.github.io/categories/%E9%95%BF%E7%9F%A5%E8%AF%86/"/>
<category term="git" scheme="http://xtutu.github.io/tags/git/"/>
<category term="Submodule" scheme="http://xtutu.github.io/tags/Submodule/"/>
<category term="pull request" scheme="http://xtutu.github.io/tags/pull-request/"/>
</entry>
<entry>
<title>Windows下的命令行工具 —— ConEmu + Babun</title>
<link href="http://xtutu.github.io/cmd-tools-in-windows/"/>
<id>http://xtutu.github.io/cmd-tools-in-windows/</id>
<published>2016-11-26T00:30:00.000Z</published>
<updated>2023-05-24T08:46:04.929Z</updated>
<content type="html"><![CDATA[<p>最近一直在Windows下做开发,自带的cmd可用性太差。<br>虽然也装了GitBash(MINGW64),但是终归和Mac下的Iterm2 + oh my zsh无法比。<br>所以就花了点时间,去寻找可以在Windows下用的类似工具。<br><strong>看了一圈之后,最后决定用ConEmu + Babun来实现。</strong><br><img src="/img/cmdtools/1.jpg"></p><span id="more"></span><hr><h2 id="ConEmu-Babun-是什么?"><a href="#ConEmu-Babun-是什么?" class="headerlink" title="ConEmu + Babun 是什么?"></a>ConEmu + Babun 是什么?</h2><ol><li>Babun 命令行工具<br>内置 oh my zsh !</li><li>ConEmu 窗口工具<br>对应 Iterm2,虽然功能差很多。。。</li></ol><h2 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h2><h3 id="ConEmu-与-Babun-集成"><a href="#ConEmu-与-Babun-集成" class="headerlink" title="ConEmu 与 Babun 集成"></a>ConEmu 与 Babun 集成</h3><p><img src="/img/cmdtools/2.jpg"></p><figure class="highlight bash"><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">参数:/icon <span class="string">"%userprofile%\.babun\cygwin\bin\mintty.exe"</span> /dir <span class="string">"%userprofile%"</span></span><br><span class="line">命令行:%userprofile%\.babun\cygwin\bin\mintty.exe /bin/env CHERE_INVOKING=1 /bin/zsh.exe</span><br></pre></td></tr></table></figure><p><strong>注意:Babun不要设置窗口的透明度,否则无法在ConEmu中显示。但是可以通过ConEmu来设置透明度</strong></p><h3 id="Babun-配置-Alias"><a href="#Babun-配置-Alias" class="headerlink" title="Babun 配置 Alias"></a>Babun 配置 Alias</h3><p>修改 vim ~/.bashrc 是无效的!!! 每次重开都需要执行一遍 source ~/.bashrc,很坑!<br><strong>好在Babun默认集成 oh my zsh,所以我们可以通过修改zsh的配置来实现这个功能!</strong></p><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></pre></td><td class="code"><pre><span class="line">vim ~/.zshrc </span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置修改</span></span><br><span class="line"><span class="built_in">alias</span> blog=<span class="string">"cd /f/mygit/blog"</span></span><br><span class="line">ZSH_THEME=<span class="string">"ys"</span> <span class="comment"># 这是我用的zsh主题</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">source</span> ~/.zshrc</span><br></pre></td></tr></table></figure><h3 id="拖动鼠标来选文字,会自动执行类似Ctrl-C-的操作"><a href="#拖动鼠标来选文字,会自动执行类似Ctrl-C-的操作" class="headerlink" title="拖动鼠标来选文字,会自动执行类似Ctrl - C 的操作"></a>拖动鼠标来选文字,会自动执行类似Ctrl - C 的操作</h3><p>一般是软件冲突导致的,将运行的各种词典关闭屏幕取词,就可以了。</p><h3 id="GBK中文乱码"><a href="#GBK中文乱码" class="headerlink" title="GBK中文乱码"></a>GBK中文乱码</h3><p>这点目前有点无解,没有找到简单的解决方式,不过好在对我的影响不大,先搁置吧。<br><strong>后记:找到一个比较取巧的方式。</strong><br><strong>利用Linux的管道功能,可以把命令的输出结果通过iconv来转码!</strong></p><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 添加一个alias</span></span><br><span class="line"><span class="built_in">alias</span> g2u=<span class="string">"iconv -f gbk -t utf8"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 执行具体的命令,如:</span></span><br><span class="line">$ ipconfig | g2u</span><br></pre></td></tr></table></figure><h2 id="进阶"><a href="#进阶" class="headerlink" title="进阶"></a>进阶</h2><p>接下去就是看Babun自带的功能。<br>如果不熟悉oh my zsh的话,也需要看看它的常见操作。</p><hr><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p>最近一直在Windows下做开发,自带的cmd可用性太差。<br>虽然也装了GitBash(MINGW64),但是终归和Mac下的Iterm2 + oh my zsh无法比。<br>所以就花了点时间,去寻找可以在Windows下用的类似工具。<br><strong>看了一圈之后,最后决定用ConEmu + Babun来实现。</strong><br><img src="/img/cmdtools/1.jpg"></p></summary>
<category term="工具" scheme="http://xtutu.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="Babun" scheme="http://xtutu.github.io/tags/Babun/"/>
<category term="ConEmu" scheme="http://xtutu.github.io/tags/ConEmu/"/>
</entry>
<entry>
<title>雨天,跑与走哪个淋雨少?模拟一下你就知道</title>
<link href="http://xtutu.github.io/run-or-walk-in-rain-day/"/>
<id>http://xtutu.github.io/run-or-walk-in-rain-day/</id>
<published>2016-05-09T05:30:00.000Z</published>
<updated>2023-05-24T09:21:09.997Z</updated>
<content type="html"><![CDATA[<p>中午吃完饭,居然下起了雨,不过好在下的不大。在回公司的路上,小k问了我上面这个问题。<br>这可有点难到我了,倒不是问题本身有多难,而是通俗的解释问题的结论有点难。<br>毕竟这个问题涉及到各种数学计算,细节太多,无法直接描述。</p><p><strong>既然计算起来比较麻烦,那就只能通过模拟实验来展示结论!</strong></p><p><img src="/img/rain/0.jpg" alt="全景"></p><span id="more"></span><p><img src="/img/rain/1.jpg" alt="操作界面描述"></p><p>接下去就是实验分析啦!</p><h1 id="先说结论"><a href="#先说结论" class="headerlink" title="先说结论"></a>先说结论</h1><p>这个问题得分为两种情况讨论。</p><ol><li>移动距离相同(这个是生活中比较常见的情景)<br><strong>跑步会比走路淋到的雨要少!</strong><br><em>如果你模拟出其它特殊情况,请给我留言 :)</em></li><li>移动时间相同<br><strong>淋雨量与人物相对于雨滴的运动方向等信息有关。</strong></li></ol><hr><h1 id="实验数据"><a href="#实验数据" class="headerlink" title="实验数据"></a>实验数据</h1><h2 id="移动距离相同"><a href="#移动距离相同" class="headerlink" title="移动距离相同"></a>移动距离相同</h2><p>走路:移动速度:2.1 m/s。 最终接触到的雨滴数:332<br><img src="/img/rain/2-1.jpg"><br>跑步:移动速度:6.9 m/s。 最终接触到的雨滴数:171<br><img src="/img/rain/2-2.jpg"></p><h2 id="移动时间相同"><a href="#移动时间相同" class="headerlink" title="移动时间相同"></a>移动时间相同</h2><h3 id="跑步比走路淋大的雨更多"><a href="#跑步比走路淋大的雨更多" class="headerlink" title="跑步比走路淋大的雨更多"></a>跑步比走路淋大的雨更多</h3><p>走路:移动速度:2.0 m/s。 最终接触到的雨滴数:52<br><img src="/img/rain/3-1.jpg"><br>跑步:移动速度:7.6 m/s。 最终接触到的雨滴数:74<br><img src="/img/rain/3-2.jpg"></p><h3 id="跑步比走路淋雨要少"><a href="#跑步比走路淋雨要少" class="headerlink" title="跑步比走路淋雨要少"></a>跑步比走路淋雨要少</h3><p>当雨滴下落方向与人物运动方向一致时,的确会出现跑步比走路淋雨要少的现象。</p><p>走路:雨滴角度:-44.5,移动速度:1 m/s。 最终接触到的雨滴数:48<br><img src="/img/rain/4-1.jpg"><br>跑步:雨滴角度:-44.5,移动速度:7.6 m/s。 最终接触到的雨滴数:36<br><img src="/img/rain/4-2.jpg"></p><h1 id="实验地址"><a href="#实验地址" class="headerlink" title="实验地址"></a>实验地址</h1><p>模拟实验在线地址:<a href="http://xtutu.github.io/html-rain/index.html">http://xtutu.github.io/html-rain/index.html</a><br><strong>chrome下可以正常展示,其它浏览器未做试验</strong><br>可能速度有点慢,耐心等待下。</p><p>本文同步发表在知乎:<br><a href="https://www.zhihu.com/question/28203487/answer/99788748?from=profile_answer_card">https://www.zhihu.com/question/28203487/answer/99788748?from=profile_answer_card</a></p><hr><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p>中午吃完饭,居然下起了雨,不过好在下的不大。在回公司的路上,小k问了我上面这个问题。<br>这可有点难到我了,倒不是问题本身有多难,而是通俗的解释问题的结论有点难。<br>毕竟这个问题涉及到各种数学计算,细节太多,无法直接描述。</p>
<p><strong>既然计算起来比较麻烦,那就只能通过模拟实验来展示结论!</strong></p>
<p><img src="/img/rain/0.jpg" alt="全景"></p></summary>
<category term="模拟" scheme="http://xtutu.github.io/categories/%E6%A8%A1%E6%8B%9F/"/>
<category term="淋雨问题" scheme="http://xtutu.github.io/tags/%E6%B7%8B%E9%9B%A8%E9%97%AE%E9%A2%98/"/>
</entry>
<entry>
<title>普通程序员、优秀程序员差距能有多大?!</title>
<link href="http://xtutu.github.io/good-coder-and-bad-coder/"/>
<id>http://xtutu.github.io/good-coder-and-bad-coder/</id>
<published>2016-04-18T12:00:00.000Z</published>
<updated>2023-05-24T08:46:04.932Z</updated>
<content type="html"><![CDATA[<p>晚上和同事小k一起吃饭回家(小k是公司的一名美术),他在路上问了我这个问题。<br>于是就有了下面的对话。</p><hr><p><strong>我:这个问题啊,我得想想怎么才能比较通俗的和你解释。(如果直接说,算法能力、架构能力强,小k肯定是听不懂的)</strong></p><p><strong>我:哦,想到了!还记的小学的数学课本上,有一则关于高斯的故事吗?大概就是说“老师布置了一道题目,让大家算出从1加到100是多少”</strong></p><p>小k:嗯,有点印象。</p><p><strong>我:对于这个问题,普通程序员,可能就是一个一个的做加法,需要运算99次。而优秀的程序员会写出(100 + 1) * 100 / 2的公式,只要3次运算就搞定了。</strong></p><p>小k有点懵,貌似不怎么理解为什么可以这样算出结果。。。</p><p><strong>于是我继续解释:你可以试着想象一下 “把1+2+…+100写在纸上,然后再在它的下一排,倒过来写100+99+…+1<br>大致就是这样:”</strong></p><blockquote><p>1+2+…+100<br>100+99+…+1</p></blockquote><p><strong>我:可以发现,上下两两相加,就变成了: 101+101+…+101。总共有100个101,因为这样算实际上是做了两次1+…+100,所以我们还需要除以2。</strong></p><p>小k似乎懂了,但是过了一会又说:等一下,为什么都是101,中间的50+50,不是应该是100吗?</p><p><strong>看到小k,问出这样的问题,我只好继续解释:1到100,是偶数个,只有奇数才有中间的那个数字,比如1,2,3。</strong></p><p>小k:哦哦哦,懂了</p><p>至此,终于向小k解释完这个问题。<br><em>如果小k去当程序员的话,应该算不上优秀… :-) 哈哈哈</em></p><span id="more"></span><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p>晚上和同事小k一起吃饭回家(小k是公司的一名美术),他在路上问了我这个问题。<br>于是就有了下面的对话。</p>
<hr>
<p><strong>我:这个问题啊,我得想想怎么才能比较通俗的和你解释。(如果直接说,算法能力、架构能力强,小k肯定是听不懂的)</strong></p>
<p><strong>我:哦,想到了!还记的小学的数学课本上,有一则关于高斯的故事吗?大概就是说“老师布置了一道题目,让大家算出从1加到100是多少”</strong></p>
<p>小k:嗯,有点印象。</p>
<p><strong>我:对于这个问题,普通程序员,可能就是一个一个的做加法,需要运算99次。而优秀的程序员会写出(100 + 1) * 100 &#x2F; 2的公式,只要3次运算就搞定了。</strong></p>
<p>小k有点懵,貌似不怎么理解为什么可以这样算出结果。。。</p>
<p><strong>于是我继续解释:你可以试着想象一下 “把1+2+…+100写在纸上,然后再在它的下一排,倒过来写100+99+…+1<br>大致就是这样:”</strong></p>
<blockquote>
<p>1+2+…+100<br>100+99+…+1</p>
</blockquote>
<p><strong>我:可以发现,上下两两相加,就变成了: 101+101+…+101。总共有100个101,因为这样算实际上是做了两次1+…+100,所以我们还需要除以2。</strong></p>
<p>小k似乎懂了,但是过了一会又说:等一下,为什么都是101,中间的50+50,不是应该是100吗?</p>
<p><strong>看到小k,问出这样的问题,我只好继续解释:1到100,是偶数个,只有奇数才有中间的那个数字,比如1,2,3。</strong></p>
<p>小k:哦哦哦,懂了</p>
<p>至此,终于向小k解释完这个问题。<br><em>如果小k去当程序员的话,应该算不上优秀… :-) 哈哈哈</em></p></summary>
<category term="长知识" scheme="http://xtutu.github.io/categories/%E9%95%BF%E7%9F%A5%E8%AF%86/"/>
<category term="程序员" scheme="http://xtutu.github.io/tags/%E7%A8%8B%E5%BA%8F%E5%91%98/"/>
</entry>
<entry>
<title>面向客户端测试与面向服务端测试</title>
<link href="http://xtutu.github.io/client-oriented-test-and-server-oriented-test/"/>
<id>http://xtutu.github.io/client-oriented-test-and-server-oriented-test/</id>
<published>2016-04-15T10:00:00.000Z</published>
<updated>2023-05-24T08:46:04.929Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>产品在早期的研发过程中,特别是初创团队,可能根本就没有专门的测试人员。(当初我参与的第一个手游项目就是这样,但也因此,项目组的程序、策划、美术每个人,都得反反复复跑游戏,充当测试的角色)。</p><p>测试是保证产品质量的一个重要环节,而测试人员本身的专业能力直接影响测试质量。<br><strong>作为程序员,经常会听到到面向对象和面向过程这类词汇。那么“测试人员”,是否也有类似的分类呢?!答案是肯定的。</strong><br>在我平时的工作中,接触到的测试人员,基本都是本文标题中所提到的面向客户端测试,能够做到面向服务端测试的寥寥无几。</p><span id="more"></span><h2 id="面向客户端测试"><a href="#面向客户端测试" class="headerlink" title="面向客户端测试"></a>面向客户端测试</h2><p>这是一项门槛非常低的工作,基本只要有点常识就能做。所需要完成的工作,无非就是拿着手机各种点点点,看看界面显示是否正常,客户端会不会崩溃。<br>有些细心的测试人员,会做的更好一些。比如:<br>根据实际的产品逻辑,想一些比较容易忽略的操作,来进一步验证软件的稳定性。</p><p><strong>但是!!! 面向客户端测试终归是有局限性的,怎么都跳不出客户端的那几个操作,那几个界面信息。</strong></p><h2 id="面向服务端测试"><a href="#面向服务端测试" class="headerlink" title="面向服务端测试"></a>面向服务端测试</h2><p>面向服务端测试(或者称为<strong>面向接口测试</strong>),这应该可以算是测试人员能力的一个分界线,可惜绝大多数测试人员都止步于此。<br><strong>这是有门槛的,需要测试人员有一定程序能力(能写脚本)和计算机方面的知识(Http、Socket通讯细节等)。</strong></p><p>这里以银行转账为例。</p><blockquote><p>用户A通过手机银行往用户B账户转账。<br>那么客户端这边在输入金额这一块肯定是需要做限制的,比如正数,小数点保留两位等。<br>但是服务端可能并没有做限制。<br>所以用户可以绕开客户端界面,直接发送转账协议,把其中的金额改成负数,这就导致用户A的金额不减反增。<br>(平时报道的很多漏洞,有不少就是这样类似的原因)</p></blockquote><p><strong>当然这只是一个玩笑,但也足够体现出跳出客户端界面约束,面向服务端测试的重要性。</strong></p><p>面向服务端测试还有很多内容,比如:性能测试。(这有点偏向服务端开发人员的工作)</p><p>当然面向服务端测试有许多现成的工具,虽然多了些学习成本,但的确可以减少测试人员的工作量。<br>(还是非常值得学习使用的!)</p><h2 id="还需要…"><a href="#还需要…" class="headerlink" title="还需要…"></a>还需要…</h2><p>以上只是具体的测试方法,而在实际项目中,测试规范也异常重要!<br>一般来说,测试流程应该是一轮一轮的完整进行,而不是一边开发,一边测试。<br><strong>“一边开发,一边测试” 本身并没有问题,但是这不能算是测试阶段,只能算作是开发阶段!<br>只要客户端与服务端功能还未全部完成,期间进行的各种测试,都不能作为产品上线的依托。</strong></p><p>当客户端,服务端代码不做修改之后,依旧需要进行一轮完整的测试!</p><p><strong>其实,测试这一职业就是简化版的程序员,也需要不断的学习充电! 共勉!!!</strong></p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>产品在早期的研发过程中,特别是初创团队,可能根本就没有专门的测试人员。(当初我参与的第一个手游项目就是这样,但也因此,项目组的程序、策划、美术每个人,都得反反复复跑游戏,充当测试的角色)。</p>
<p>测试是保证产品质量的一个重要环节,而测试人员本身的专业能力直接影响测试质量。<br><strong>作为程序员,经常会听到到面向对象和面向过程这类词汇。那么“测试人员”,是否也有类似的分类呢?!答案是肯定的。</strong><br>在我平时的工作中,接触到的测试人员,基本都是本文标题中所提到的面向客户端测试,能够做到面向服务端测试的寥寥无几。</p></summary>
<category term="长知识" scheme="http://xtutu.github.io/categories/%E9%95%BF%E7%9F%A5%E8%AF%86/"/>
<category term="测试" scheme="http://xtutu.github.io/tags/%E6%B5%8B%E8%AF%95/"/>
</entry>
<entry>
<title>Atom使用体验</title>
<link href="http://xtutu.github.io/atom-experience/"/>
<id>http://xtutu.github.io/atom-experience/</id>
<published>2016-03-14T12:00:00.000Z</published>
<updated>2023-05-24T08:46:04.929Z</updated>
<content type="html"><![CDATA[<p>后记:已用<strong>VSCode</strong>代替,因为所用的硬盘不是SSD,Atom在大项目上的表现实在是卡…</p><p>很早很早之前看到有服务端的同事在用<a href="https://atom.io/">Atom编辑器</a>,当时还是蛮吃惊的。<br>因为印象中的Atom,就是一个拥有高贵血统的体验产品:背景强大,理念前卫,但是Bug还比较多,并不适合作为首选的IDE。</p><p>这两天正好有空,就折腾了下。用下来,感觉还是很不错的! </p><span id="more"></span><p>先来一张截图。(我使用的版本是:1.6.0-beta8)<br><img src="/img/20160309114725.jpg"></p><p>Atom的插件系统,非常强大!可以这么说:使用Atom,就是使用它的各种插件。<br>附上自己使用的插件:</p><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></pre></td><td class="code"><pre><span class="line">C:\Users\Administrator\.atom\packages (16)</span><br><span class="line">├── activate-power-mode@0.4.1 应该都看到过这个插件的新闻</span><br><span class="line">├── atom-beautify@0.28.26 代码格式化</span><br><span class="line">├── atom-ternjs@0.13.2 js语法提示</span><br><span class="line">├── autoclose-html@0.23.0 html自动补齐</xxx></span><br><span class="line">├── autocomplete-paths@1.0.2 自动提示路径</span><br><span class="line">├── color-picker@2.1.1 选择颜色</span><br><span class="line">├── eclipse-keybindings@0.9.0 绑定Eclipse快捷键</span><br><span class="line">├── file-icons@1.6.18 给TreeView添加文件小icon</span><br><span class="line">├── git-plus@5.13.0 git操作相关</span><br><span class="line">├── goto-definition@1.1.12 js跳转到定义</span><br><span class="line">├── highlight-selected@0.11.2 选中相同字符串高亮</span><br><span class="line">├── last-cursor-position@0.9.0 增加前进回退功能</span><br><span class="line">├── linter@1.11.3 语法提示</span><br><span class="line">├── linter-jshint@2.0.2 js语法提示</span><br><span class="line">├── markdown-themeable-pdf@0.10.2 把markdown 生成 pdf</span><br><span class="line">├── minimap@4.20.0 缩略面板(用过sublime的应该都知道)</span><br><span class="line">├── minimap-autohide@0.10.1 minimap的插件</span><br><span class="line">├── open-recent@5.0.0 添加菜单:最近打开的目录</span><br><span class="line">├── pdf-view@0.50.0 预览pdf</span><br><span class="line">├── sync-settings@0.6.0 同步Atom设置!</span><br><span class="line">└── terminal-plus@0.14.5 集成命令行终端</span><br></pre></td></tr></table></figure><p><strong>装了这些插件之后,基本就可以随心所欲的写代码了!</strong></p><p><strong>接下去就是了解各种配置,除了<a href="https://discuss.atom.io/">官方社区</a>,大家可以在<a href="https://atom-china.org/">Atom的中文社区</a>学习各种姿势!</strong></p><p>目前不完善的地方: </p><ol><li>单个文件如果有个几万行会很卡,甚至会Crash </li><li>文件数目比较多,跳转检索会很慢<br><strong>反正就是对大项目支持很不友好,希望之后能改善吧。。。</strong></li></ol><p>我目前的习惯是:</p><ol><li>简单的文本编辑 :sublime</li><li>小项目、写博客等 :Atom</li><li>实际开发 : Webstorm 和 Atom 搭配使用<br>*有人看的时候,用Atom;没人看的时候,用WebStrom :) *</li></ol><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p>后记:已用<strong>VSCode</strong>代替,因为所用的硬盘不是SSD,Atom在大项目上的表现实在是卡…</p>
<p>很早很早之前看到有服务端的同事在用<a href="https://atom.io/">Atom编辑器</a>,当时还是蛮吃惊的。<br>因为印象中的Atom,就是一个拥有高贵血统的体验产品:背景强大,理念前卫,但是Bug还比较多,并不适合作为首选的IDE。</p>
<p>这两天正好有空,就折腾了下。用下来,感觉还是很不错的! </p></summary>
<category term="工具" scheme="http://xtutu.github.io/categories/%E5%B7%A5%E5%85%B7/"/>
<category term="atom" scheme="http://xtutu.github.io/tags/atom/"/>
<category term="编辑器" scheme="http://xtutu.github.io/tags/%E7%BC%96%E8%BE%91%E5%99%A8/"/>
</entry>
<entry>
<title>InfluxDB简明手册 初稿完成了!</title>
<link href="http://xtutu.github.io/influxDB-handbook-finished/"/>
<id>http://xtutu.github.io/influxDB-handbook-finished/</id>
<published>2016-02-26T12:00:00.000Z</published>
<updated>2023-05-24T08:46:04.933Z</updated>
<content type="html"><![CDATA[<p><em>InfluxDB简明手册 操作教程 中文文档。</em> </p><p>手册不断完善中,欢迎 <strong>pull request!</strong><br><strong>如果对你有所帮助,请给一个Star!</strong><br>项目地址: <a href="https://github.com/xtutu/influxdb-handbook">https://github.com/xtutu/influxdb-handbook</a></p><hr><p>手册在线地址: <a href="https://www.gitbook.com/read/book/xtutu/influxdb-handbook">https://www.gitbook.com/read/book/xtutu/influxdb-handbook</a> </p><p><img src="/img/20160226164436.jpg"></p><span id="more"></span><p>写这本手册有两个目的: </p><ol><li>作为自己的学习influxDB的笔记 </li><li>顺便了解下gitbook的使用</li></ol><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p><em>InfluxDB简明手册 操作教程 中文文档。</em> </p>
<p>手册不断完善中,欢迎 <strong>pull request!</strong><br><strong>如果对你有所帮助,请给一个Star!</strong><br>项目地址: <a href="https://github.com/xtutu/influxdb-handbook">https://github.com/xtutu/influxdb-handbook</a></p>
<hr>
<p>手册在线地址: <a href="https://www.gitbook.com/read/book/xtutu/influxdb-handbook">https://www.gitbook.com/read/book/xtutu/influxdb-handbook</a> </p>
<p><img src="/img/20160226164436.jpg"></p></summary>
<category term="长知识" scheme="http://xtutu.github.io/categories/%E9%95%BF%E7%9F%A5%E8%AF%86/"/>
<category term="InfluxDB" scheme="http://xtutu.github.io/tags/InfluxDB/"/>
<category term="教程" scheme="http://xtutu.github.io/tags/%E6%95%99%E7%A8%8B/"/>
<category term="文档" scheme="http://xtutu.github.io/tags/%E6%96%87%E6%A1%A3/"/>
</entry>
<entry>
<title>Egret源码分析-触摸机制</title>
<link href="http://xtutu.github.io/egret-source-part-touch-event/"/>
<id>http://xtutu.github.io/egret-source-part-touch-event/</id>
<published>2016-02-24T14:30:00.000Z</published>
<updated>2023-05-24T08:46:04.931Z</updated>
<content type="html"><![CDATA[<h2 id="Egret中的触摸机制"><a href="#Egret中的触摸机制" class="headerlink" title="Egret中的触摸机制"></a>Egret中的触摸机制</h2><p>距离上次写Egret的东西,已经过了好久。其实这篇文章很早之前就写了一些,但是一直没有整理,所以一直没有发上来。这两天刚好有时间,就整理了下。</p><blockquote><p>所使用的Egret版本:3.0.2。</p></blockquote><span id="more"></span><p>在Egret中采用了采用冒泡的事件机制(官方有说明:和Flash中的机制类似)。<br>事件流主要有三个阶段:</p><ol><li>捕获 stage -> node</li><li>目标 node</li><li>冒泡 node -> stage</li></ol><p><strong>一个完整的事件流顺序:捕获阶段→目标阶段→冒泡阶段。(stage -> node -> stage)</strong><br>Egret中触摸事件默认是冒泡的。能否触发,并不是说一定要触摸点落在父节点里,只要目标节点被点中,就可以按这个规则来算</p><p>添加一个事件的方法如下:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">addEventListener</span>(<span class="attr">type</span>: string, <span class="attr">listener</span>: <span class="title class_">Function</span>, <span class="attr">thisObject</span>: any, useCapture?: boolean, priority?: number)</span><br></pre></td></tr></table></figure><p><strong>注意:Egret框架的事件流与Flash实现并不一致。</strong><br>在Flash中,默认的的事件监听若不开启useCapture将监听目标和冒泡阶段。若开启capture将只能监听捕获但不包括目标的事件。而在Egret中,是包括目标事件的!</p><ol><li><p>关于捕获<br>seCaptureu默认是false: 表示只存在目标和冒泡阶段。<br>设为true,则表示只存在捕获阶段和目标阶段(在Flash中则是不包含目标阶段)。<br><em>如果调用两次addEventListener,分别将seCapture设为true 和 false,那么目标状态会触发两次回调</em></p></li><li><p>关于冒泡<br>1、子级发送事件冒泡,各层父级不捕获也能接收,即在冒泡阶段接收,顺序为从内至外(子→父);<br>2、子级发送事件不冒泡,只有父级捕获,才能接收,即在捕获阶段接收,顺序为从外至内(父→子);</p></li></ol><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="Egret中的触摸机制"><a href="#Egret中的触摸机制" class="headerlink" title="Egret中的触摸机制"></a>Egret中的触摸机制</h2><p>距离上次写Egret的东西,已经过了好久。其实这篇文章很早之前就写了一些,但是一直没有整理,所以一直没有发上来。这两天刚好有时间,就整理了下。</p>
<blockquote>
<p>所使用的Egret版本:3.0.2。</p>
</blockquote></summary>
<category term="Egret" scheme="http://xtutu.github.io/categories/Egret/"/>
<category term="Egret" scheme="http://xtutu.github.io/tags/Egret/"/>
<category term="触摸" scheme="http://xtutu.github.io/tags/%E8%A7%A6%E6%91%B8/"/>
<category term="事件流" scheme="http://xtutu.github.io/tags/%E4%BA%8B%E4%BB%B6%E6%B5%81/"/>
<category term="捕获" scheme="http://xtutu.github.io/tags/%E6%8D%95%E8%8E%B7/"/>
<category term="冒泡" scheme="http://xtutu.github.io/tags/%E5%86%92%E6%B3%A1/"/>
</entry>
<entry>
<title>技术正变得不再是门槛</title>
<link href="http://xtutu.github.io/technology-is-not-threshold-any-more/"/>
<id>http://xtutu.github.io/technology-is-not-threshold-any-more/</id>
<published>2016-02-24T12:00:00.000Z</published>
<updated>2016-02-24T12:00:00.000Z</updated>
<content type="html"><![CDATA[<p>我有一个很棒的想法,现在只缺一个美术妹子了!<br><img src="/img/fd039245d688d43fba7134327f1ed21b0ff43b11.jpg" alt="这是一张图片"></p><span id="more"></span><p>技术正变得越来越不是门槛,不管是服务端,还是游戏客户端。</p><hr><h2 id="服务端"><a href="#服务端" class="headerlink" title="服务端"></a>服务端</h2><p>之前在 <a href="http://xtutu.github.io/think-about-server">《服务端架构的一些思考》</a>中有提到:“在分布式环境中,数据库框架搭建会比较复杂”。<br>以MongoDB为例,如果要搭一个比较大型的数据库框架,基本会采用分片技术<br>最终的结构可能是这个样子:</p><ol><li>3个mongos(数据库集群请求的入口)</li><li>3个config server(配置服务器)</li><li>3个shard server(数据分片): 每个分片再配3个副本集,也就说这里有9个server</li></ol><p><strong>这样一算,我们得需要配置15台server(一个物理服务器上可以放多个server),才算是搭了一个不错的框架!</strong><br><em>除此之外,数据的备份与恢复都是一大难题。</em></p><p>但是现在这种技术解决方案,都有第三方云平台(比如:阿里云)提供了。包括之前在<a href="http://xtutu.github.io/to-be-a-high-level-of-appearance-of-the-programmer">《做一名“高颜值”的程序员》</a>中提到的监控服务。</p><blockquote><p>想当初大学期间,自己如果需要在外网部署一个简单的服务器,用的比较多的就是SAE,当时功能也比较少</p></blockquote><hr><h2 id="游戏客户端"><a href="#游戏客户端" class="headerlink" title="游戏客户端"></a>游戏客户端</h2><blockquote><p>在早期,一些游戏会有这样的宣传语:“采用XX引擎,XX技术实现!”<br>而玩家在论坛中讨论某款大作的时候,也会提及。</p></blockquote><p>在Unity3D、Unreal中,对美术和策划都有着非常不错的支持。现在的游戏引擎也越来越完善:物理引擎,各种编辑器,跨平台。。。<br>我们不再需要非常强大的编程能力,就能做出一款畅销的游戏产品(有不少关于“美术做出畅销游戏”的案例)。</p><hr><h2 id="技术的最终是不是走向产品呢?"><a href="#技术的最终是不是走向产品呢?" class="headerlink" title="技术的最终是不是走向产品呢?"></a>技术的最终是不是走向产品呢?</h2><p>当实现一款产品没有任何技术难题的时候,开发人似乎应该往产品经理上靠。</p><h2 id="期待更叼的技术出现!"><a href="#期待更叼的技术出现!" class="headerlink" title="期待更叼的技术出现!"></a>期待更叼的技术出现!</h2><p>IT中产品的发展规律似乎是一个循环:<br>拼技术->拼产品->拼技术</p><p><strong>期待VR普及!</strong><br><strong>期待各种高科技!</strong></p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p>我有一个很棒的想法,现在只缺一个美术妹子了!<br><img src="/img/fd039245d688d43fba7134327f1ed21b0ff43b11.jpg" alt="这是一张图片"></p></summary>
<category term="碎语" scheme="http://xtutu.github.io/categories/%E7%A2%8E%E8%AF%AD/"/>
<category term="技术门槛" scheme="http://xtutu.github.io/tags/%E6%8A%80%E6%9C%AF%E9%97%A8%E6%A7%9B/"/>
</entry>
<entry>
<title>做一名“高颜值”的程序员</title>
<link href="http://xtutu.github.io/to-be-a-high-level-of-appearance-of-the-programmer/"/>
<id>http://xtutu.github.io/to-be-a-high-level-of-appearance-of-the-programmer/</id>
<published>2016-02-18T12:00:00.000Z</published>
<updated>2023-05-24T08:46:04.935Z</updated>
<content type="html"><![CDATA[<p><img src="/img/highapperance/220JGN7-0.jpg" alt="这是一张图片"></p><p>颜值高总是能带来不少便利,不过作为程序员,绝大多数都显得比较朴素,和高颜值这三个字不怎么挂的上钩。<br><strong>那么颜值不够怎么办?工具凑!</strong></p><span id="more"></span><p>下面我就介绍一些可以提高程序员“颜值”的软硬件!</p><hr><h1 id="硬件设施"><a href="#硬件设施" class="headerlink" title="硬件设施"></a>硬件设施</h1><h2 id="HHKB键盘"><a href="#HHKB键盘" class="headerlink" title="HHKB键盘"></a>HHKB键盘</h2><p>程序员在工作中,接触最多的也就是键盘了。HHKB作为一款电容键盘,可谓极为小巧!<br>即使你没用过这款键盘,想必也看过不少它的消息。<br><strong>为什么推荐它呢!先来看看都有谁用过这款键盘!</strong></p><ol><li>GNU 之父 Richard Stallman<br><img src="/img/highapperance/asdfff.jpg" alt="这是一张图片"></li><li>C++ 之父 Bjarne Stroustrup<br><img src="/img/highapperance/sdfasddd.jpg" alt="这是一张图片"></li><li>还有我…<br><img src="/img/highapperance/20160218120353.jpg" alt="这是一张图片"></li></ol><hr><h2 id="MacBook"><a href="#MacBook" class="headerlink" title="MacBook"></a>MacBook</h2><p><img src="/img/highapperance/20160218120532.jpg" alt="这是一张图片"></p><blockquote><footer><strong>[图片来自百度贴吧用户qwe768932]</strong></footer></blockquote><p>橘黄色的灯光、bose mini、macbook、再来一杯咖啡,真实文艺十足,逼格满满啊。<br>当然这里并不是说一定要买一个MacBook,而是希望如果可以用mac系统做开发,就别用windows了。不是说window不好,而是mac的确更适合开发人员。<br><strong>后面介绍的一些软件都可以非常方便的在mac上安装</strong></p><hr><h1 id="软件设施—这是重点!"><a href="#软件设施—这是重点!" class="headerlink" title="软件设施—这是重点!"></a>软件设施—这是重点!</h1><p><strong>虽然美术妹子看不懂你写的代码,但是她们看的到你的屏幕!!!</strong></p><p>人们常说第一印象很重要,第一印象看什么?当然是看外表。而计算机屏幕上的画面,就是程序员的外表!</p><p>以下推荐的工具,它们不但可以靠脸吃饭,功能也是异常强大!!!<br><strong>当然它们也是有一定学习成本的!</strong></p><!-- 太常见的工具,我就不单独介绍了,比如1. sublime 文本编辑器。 (最近的Atom貌似更吊,还没怎么用过) --><h2 id="iterms2-zsh"><a href="#iterms2-zsh" class="headerlink" title="iterms2 + zsh"></a>iterms2 + zsh</h2><p>这是比Mac系统原生terminal好一百倍的替代品!效果如下:<br><img src="/img/highapperance/efluo4M.png"></p><hr><h2 id="Atom编辑器"><a href="#Atom编辑器" class="headerlink" title="Atom编辑器"></a>Atom编辑器</h2><p>官方口号:”A hackable text editor for the 21st Century”<br>它有一个好爸爸,界面很不错!<br><em>美中不足的是,目前版本(1.6.0 beta8)对于大文件(上万行)和大项目支持还不是很友好。</em><br>附上我的使用心得: <a href="http://xtutu.github.io/atom-experience">http://xtutu.github.io/atom-experience</a></p><hr><h2 id="swagger"><a href="#swagger" class="headerlink" title="swagger"></a>swagger</h2><p><img src="/img/highapperance/20160218170522.jpg"><br>这是一款展示http restful api的web界面。<br>Demo : <a href="http://petstore.swagger.io/">http://petstore.swagger.io/</a><br>在用这个工具之前,我都是把协议写在文本文件里面的。。。<br>用了这个之后,瞬间就高大上了,它还能直接发送对应的api请求!!!</p><hr><h2 id="grafana"><a href="#grafana" class="headerlink" title="grafana"></a>grafana</h2><p><img src="/img/highapperance/20160218170441.jpg"><br>它主要用来做实时数据的展示。<br>(注意:这是一个展示工具!具体的数据收集可以用Elasticsearch、InfluxDB等数据库)<br>它可以:</p><ol><li>展示服务器的运行状态</li><li>展示restful api的运行时间</li><li>展示一年的天气温度</li><li>展示其它一些随时间变化的各种数据</li></ol><p><strong>看看它的宣传语!</strong></p><blockquote><p><strong>The leading graph and dashboard builder for visualizing time series metrics.</strong></p></blockquote><p>Demo : <a href="http://play.grafana.org/">http://play.grafana.org/</a></p><hr><h1 id="待补充,持续更新…"><a href="#待补充,持续更新…" class="headerlink" title="待补充,持续更新…"></a>待补充,持续更新…</h1><p>先写这么多,本文将持续更新,大家如果知道哪些功能强大,<strong>颜值又高</strong>的工具,欢迎给我留言!</p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><p><img src="/img/highapperance/220JGN7-0.jpg" alt="这是一张图片"></p>
<p>颜值高总是能带来不少便利,不过作为程序员,绝大多数都显得比较朴素,和高颜值这三个字不怎么挂的上钩。<br><strong>那么颜值不够怎么办?工具凑!</strong></p></summary>
<category term="长知识" scheme="http://xtutu.github.io/categories/%E9%95%BF%E7%9F%A5%E8%AF%86/"/>
</entry>
<entry>
<title>走出地球,飞向太空!</title>
<link href="http://xtutu.github.io/about-human-future/"/>
<id>http://xtutu.github.io/about-human-future/</id>
<published>2016-02-17T12:57:46.000Z</published>
<updated>2023-05-24T08:46:04.927Z</updated>
<content type="html"><![CDATA[<blockquote><p>“给时光以生命,给岁月以文明。”<br>——刘慈欣《三体》</p></blockquote><hr><span id="more"></span><blockquote><p>“大多数人到死都没有向尘世之外瞥一眼。”<br>——刘慈欣《三体》</p></blockquote><hr><blockquote><p>“越透明的东西越神秘,宇宙本身就是透明的,只要目力能及,你想看多远就看多远,但越看越神秘。”<br>——刘慈欣《三体》</p></blockquote><hr><blockquote><p>“海中的鱼走上了陆地,从一片黑暗森林奔向另一片黑暗森林。”<br>——刘慈欣《三体》</p></blockquote><hr><p><strong>人类首次探测到了引力波!!!</strong><br>虽然不是专业人士,但是当我看到这则消息的时候,依旧觉得这是一个新时代的开始。</p><p>小时候,老师问我们长大了想要做什么职业。据说绝大多是人都是回答科学家。<br>我也免不了俗,不过当时,我的回答是<strong>天文学家</strong>。<br>从小就对宇宙,外星球,UFO特别感兴趣。哪怕是现在,虽然是一名普普通通的程序员,但是在夜里,每当我抬头仰望这浩瀚星空时,总会觉得自己特别渺小,甚至有点害怕。偌大一个宇宙中,生命似乎特别孤独。</p><p><em>我一直坚信在宇宙中,存在比我们人类更高级的生物。</em></p><p><strong>人类终归是要飞出地球的,这么大的宇宙等着我们探索呢!</strong></p><hr><p>有时候真的不想生活在现在这个时代,希望自己能够再过个几百年,等科技发展到人类可以自由探索宇宙的时候再出生。那样真的是该多好,要知道就连电灯都是在100多年前才被发明的,科技的发展速度真的是太快了。</p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><blockquote>
<p>“给时光以生命,给岁月以文明。”<br>——刘慈欣《三体》</p>
</blockquote>
<hr></summary>
<category term="碎语" scheme="http://xtutu.github.io/categories/%E7%A2%8E%E8%AF%AD/"/>
</entry>
<entry>
<title>Promise又一个异步编程解决方案!</title>
<link href="http://xtutu.github.io/about-promise/"/>
<id>http://xtutu.github.io/about-promise/</id>
<published>2016-02-02T11:00:00.000Z</published>
<updated>2023-05-24T08:46:04.927Z</updated>
<content type="html"><![CDATA[<h2 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h2><p>2016-11-XX<br>时隔大半年,JS真的是太强大了,现在都能用 React-Native 来写App了。<br>而Promise也的确是出现在了各种库中,还有本文末提到的async & await也可以在 React-Native 中直接使用。<br>真是太方便了!(文末的吐槽随便看看吧,当时还只是针对NodeJS而言)</p><hr><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在NodeJS开发中,各种异步操作是不可避免的(好吧,这句明显是废话…)。<br>开发人员在异步编程上有各种各样的解决方案可以选择。我之前一直用的是: <a href="https://github.com/caolan/async">Async</a>这个库(star数量已经上万了)。但是,最近看到很多关于Promise的介绍,甚至连ES6里面都内置了这个东西。感觉自己不会用都有点不好意思…</p><span id="more"></span><h2 id="Promise对象"><a href="#Promise对象" class="headerlink" title="Promise对象"></a>Promise对象</h2><p>之前其实看过一点Promise相关的内容,但是并不喜欢它处理异步操作的方式(各种Promise对象),所以就一直拖延下去了…<br>现在马上就要过春节了,手头的事情也少了很多,就抽了点时间看了下。</p><h3 id="教程地址"><a href="#教程地址" class="headerlink" title="教程地址"></a>教程地址</h3><p>Promise已经出来有一段时间了,很多公司的技术团队博客里面也都写了不少它的教程:</p><ol><li><a href="http://efe.baidu.com/blog/promises-anti-pattern/">百度的EFE团队</a></li><li><a href="http://tech.meituan.com/promise-insight.html">美团的技术团队</a></li></ol><p>所以我也没必要再重复的造轮子了,<strong>这里推荐很不错教程,有点循序渐进的味道:</strong><br><a href="http://liubin.org/promises-book/">http://liubin.org/promises-book/</a></p><p>看了这篇教程之后,再对比着看看前面两个博客的地址,理解起来会更加全面。</p><h3 id="笔记"><a href="#笔记" class="headerlink" title="笔记"></a>笔记</h3><p>附上两段代码。<strong>把这两段代码理清楚,基本使用就完全没问题了。</strong></p><h4 id="代码1"><a href="#代码1" class="headerlink" title="代码1"></a>代码1</h4><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><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 一个简单的Promise</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">asyncFunction</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="keyword">function</span> (<span class="params">resolve, reject</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><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"3"</span>)</span><br><span class="line"> <span class="title function_">resolve</span>(<span class="string">'aaa'</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"4"</span>)</span><br><span class="line"> }, <span class="number">1000</span>);</span><br><span class="line"> });</span><br><span class="line">}</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">0</span>)</span><br><span class="line"><span class="title function_">asyncFunction</span>().<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">value</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"5 :"</span> , value);</span><br><span class="line">}).<span class="title function_">catch</span>(<span class="keyword">function</span> (<span class="params">error</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"error :"</span>, error);</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">2</span>)</span><br><span class="line"><span class="comment">/////////输出//////////</span></span><br><span class="line"><span class="number">0</span></span><br><span class="line"><span class="number">1</span></span><br><span class="line"><span class="number">2</span> <span class="comment">// 输出2之后,会停顿1秒</span></span><br><span class="line"><span class="comment">// 等待1秒</span></span><br><span class="line"><span class="number">3</span></span><br><span class="line"><span class="number">4</span></span><br><span class="line"><span class="number">5</span> : aaa</span><br></pre></td></tr></table></figure><p><strong>小结:</strong><br>不管是否提供了then之类的方法,Promise本身都会执行。<br>当调用then方法时,会判断任务是否已经完成了。<br><strong>如果完成了,则根据完成的状态,在本轮“事件循环”(event loop)结束时(见代码2),调用then中对应的回调。</strong><br><strong>否则就把then方法中的回调加到队列中,直到Promise完成(调用resolve or reject),再触发对应的回调。</strong></p><h4 id="代码2"><a href="#代码2" class="headerlink" title="代码2"></a>代码2</h4><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><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 简易的记录下事件循环处于第几次</span></span><br><span class="line"><span class="keyword">var</span> frame = <span class="number">0</span>;</span><br><span class="line"><span class="built_in">setInterval</span>(<span class="keyword">function</span>(<span class="params"></span>){</span><br><span class="line"> frame++;</span><br><span class="line">}, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="keyword">function</span>(<span class="params"></span>){</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"5 =>>> frame"</span>, frame);</span><br><span class="line">},<span class="number">0</span>);</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">doubleUp</span>(<span class="params">value</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"3 =>>> frame"</span>,frame);</span><br><span class="line"> <span class="keyword">return</span> value * <span class="number">2</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">output</span>(<span class="params">value</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"4 =>>> frame"</span>, frame);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> promise = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="keyword">function</span> (<span class="params">resolve, reject</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"1 =>>> frame"</span>, frame)</span><br><span class="line"> <span class="title function_">resolve</span>(<span class="number">100</span>);</span><br><span class="line">});</span><br><span class="line"><span class="keyword">var</span> promise1 = promise.<span class="title function_">then</span>(doubleUp);</span><br><span class="line"><span class="keyword">var</span> promise2 = promise1.<span class="title function_">then</span>(output);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"2 =>>> frame"</span>, frame)</span><br><span class="line"><span class="comment">/////////输出//////////</span></span><br><span class="line"><span class="number">1</span> =>>> frame <span class="number">0</span></span><br><span class="line"><span class="number">2</span> =>>> frame <span class="number">0</span></span><br><span class="line"><span class="number">3</span> =>>> frame <span class="number">0</span></span><br><span class="line"><span class="number">4</span> =>>> frame <span class="number">0</span></span><br><span class="line"><span class="number">5</span> =>>> frame <span class="number">1</span></span><br></pre></td></tr></table></figure><p><strong>小结:</strong></p><ul><li><p><strong>then方法中的回调总是是异步进行的。 then接受的参数是函数!如果是其它类型的数据,promise会忽视掉。</strong></p></li><li><p><strong>每个方法中 return 的值不仅只局限于字符串或者数值类型,也可以是对象或者promise对象等复杂类型。</strong><br>return的值会由 Promise.resolve(return的返回值); 进行相应的包装处理,<br>而“Promise.resolve(42)” 则是以下代码的语法糖。</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></pre></td><td class="code"><pre><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="title function_">resolve</span>(<span class="number">42</span>);</span><br><span class="line">});</span><br></pre></td></tr></table></figure></li><li><p><strong>catch只是 promise.then(undefined, onRejected) 的别名而已。</strong><br>推荐用用catch来实现异常捕获:promise.then(onFulfilled).catch(onRejected)<br>因为onRejected方法不能捕获同一个then方法中的onFulfilled的异常。</p></li></ul><h2 id="吐槽"><a href="#吐槽" class="headerlink" title="吐槽"></a>吐槽</h2><p><del>Promise给我的印象,其实并不好,目前应该也不会马上把它用到项目里面来。一方面是因为Async用的非常顺手,而Promise功能非常有限,特别是遍历Promise对象数组的时候。在Async模块中有各种各样的方法:each、series、reduce、parallel…</del><br><del>而用Promise来实现这些功能,就有点复杂了,不过也有第三方库在Promise规范上,添加了不少功能。比如:</del><br><del>1. <strong>bluebird</strong> : <a href="https://github.com/petkaantonov/bluebird">https://github.com/petkaantonov/bluebird</a></del><br><del>2. <strong>q</strong> : <a href="https://github.com/kriskowal/q">https://github.com/kriskowal/q</a></del></p><p><del>大家可以选一个看着顺眼的来用。</del><br><del>同时:Promise处理异步操作,最底层就是靠回调函数,但是它硬是搞了一层嵌套,把每一个异步操作都封装为一个Promise对象,淡化回掉的概念。这理解起来就真的没那么顺畅了…</del></p><hr><p>哦,对了。在ES7中支持了async和await关键字,貌似与Promise更配。<br>之后有空,再看看吧。(<strong>这个async和提到的Async模块可不是同一个东西!!!</strong>)</p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h2><p>2016-11-XX<br>时隔大半年,JS真的是太强大了,现在都能用 React-Native 来写App了。<br>而Promise也的确是出现在了各种库中,还有本文末提到的async &amp; await也可以在 React-Native 中直接使用。<br>真是太方便了!(文末的吐槽随便看看吧,当时还只是针对NodeJS而言)</p>
<hr>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>在NodeJS开发中,各种异步操作是不可避免的(好吧,这句明显是废话…)。<br>开发人员在异步编程上有各种各样的解决方案可以选择。我之前一直用的是: <a href="https://github.com/caolan/async">Async</a>这个库(star数量已经上万了)。但是,最近看到很多关于Promise的介绍,甚至连ES6里面都内置了这个东西。感觉自己不会用都有点不好意思…</p></summary>
<category term="NodeJS" scheme="http://xtutu.github.io/categories/NodeJS/"/>
<category term="Promise" scheme="http://xtutu.github.io/tags/Promise/"/>
<category term="Async" scheme="http://xtutu.github.io/tags/Async/"/>
</entry>
<entry>
<title>关于RSA、公钥、私钥、加密、签名的那些概念</title>
<link href="http://xtutu.github.io/about-rsa-public-key-private-key/"/>
<id>http://xtutu.github.io/about-rsa-public-key-private-key/</id>
<published>2016-01-28T11:00:00.000Z</published>
<updated>2023-05-24T08:46:04.928Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>作为一名程序员,经常会听到加密解密之类的词。而非对称加密技术,应用的非常广泛。本文不写加密技术的原理,只是希望以一个简单的类比,让大家了解非对称加密中常见词的概念,以及它的作用。</p><span id="more"></span><h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>在RSA算法中,有两种加密解密的方式:</p><ol><li>公钥加密,私钥解密(加密算法)</li><li>私钥加密,公钥解密(签名认证算法)<br>这两种不同的方式,有不一样的作用。</li></ol><p>我们可以做如下的类比:</p><ol><li>公钥 -> 保险箱</li><li>私钥 -> 保险箱的密码</li></ol><p>这里需要注意的是,一个密码可以打开所有用这个密码的保险箱!!!<br>私钥只有自己知道,而公钥则是公开的。</p><h3 id="公钥加密私钥解密"><a href="#公钥加密私钥解密" class="headerlink" title="公钥加密私钥解密"></a>公钥加密私钥解密</h3><p>这个过程,就是我们把东西放到保险箱里面,只有拥有密码的人,才能打开保险箱,知道里面到底是什么东西。<br>信息传递是从公钥这边传给私钥。因为别人没有私钥,就无法解密具体的信息是什么。</p><h3 id="私钥加密公钥解密"><a href="#私钥加密公钥解密" class="headerlink" title="私钥加密公钥解密"></a>私钥加密公钥解密</h3><p>这种加密方式主要用于身份认证,用于确定你是不是这个保险箱的主人。<br>比较常见的就是,我们在Github中的添加SSH公钥这一行为。<br>我们把公钥告诉Github,然后通过私钥去访问,发现可以打开这个保险箱,所以就能确定我具有这个Github仓库的访问权限。<br>信息传递是从私钥这边传给公钥。</p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>作为一名程序员,经常会听到加密解密之类的词。而非对称加密技术,应用的非常广泛。本文不写加密技术的原理,只是希望以一个简单的类比,让大家了解非对称加密中常见词的概念,以及它的作用。</p></summary>
<category term="长知识" scheme="http://xtutu.github.io/categories/%E9%95%BF%E7%9F%A5%E8%AF%86/"/>
<category term="RSA" scheme="http://xtutu.github.io/tags/RSA/"/>
<category term="公钥" scheme="http://xtutu.github.io/tags/%E5%85%AC%E9%92%A5/"/>
<category term="私钥" scheme="http://xtutu.github.io/tags/%E7%A7%81%E9%92%A5/"/>
<category term="非对称加密" scheme="http://xtutu.github.io/tags/%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86/"/>
</entry>
<entry>
<title>NodeJS中require,module,exports的关系</title>
<link href="http://xtutu.github.io/nodejs-require-module-exports/"/>
<id>http://xtutu.github.io/nodejs-require-module-exports/</id>
<published>2015-12-31T12:00:00.000Z</published>
<updated>2023-05-24T08:46:04.933Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>作为NodeJS的开发人员,想必都知道NodeJS主要通过require,exports这两个关键字将代码中的各个模块组合到一起。其中具体的机制,之前也大致看过,但是一直没有完整的整理过一遍。本文就从运行一个NodeJS脚本开始,把NodeJS加载脚本的过程梳理一遍,算是当作自己的笔记吧。</p><span id="more"></span><h2 id="记录"><a href="#记录" class="headerlink" title="记录"></a>记录</h2><h3 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h3><p>我这边的NodeJS版本是</p><figure class="highlight bash"><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">$ node -v</span><br><span class="line">v5.3.0</span><br></pre></td></tr></table></figure><p>编写一个test.js文件。是的,里面就写这一句话。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">require</span>()</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></pre></td><td class="code"><pre><span class="line">$ node test.js</span><br><span class="line"></span><br><span class="line">assert.js:89</span><br><span class="line"> throw new assert.AssertionError({</span><br><span class="line"> ^</span><br><span class="line">AssertionError: missing path</span><br><span class="line"> at Module.require (module.js:352:3)</span><br><span class="line"> at require (internal/module.js:12:17)</span><br><span class="line"> at Object.<anonymous> (f:\work\<span class="built_in">test</span>\nodejs\test.js:1:63)</span><br><span class="line"> at Module._compile (module.js:398:26)</span><br><span class="line"> at Object.Module._extensions..js (module.js:405:10)</span><br><span class="line"> at Module.load (module.js:344:32)</span><br><span class="line"> at Function.Module._load (module.js:301:12)</span><br><span class="line"> at Function.Module.runMain (module.js:430:10)</span><br><span class="line"> at startup (node.js:141:18)</span><br><span class="line"> at node.js:980:3</span><br></pre></td></tr></table></figure><h3 id="堆栈解析"><a href="#堆栈解析" class="headerlink" title="堆栈解析"></a>堆栈解析</h3><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// NodeJS通过startup方法初始化,然后进入了Module的runMain方法</span></span><br><span class="line"><span class="title class_">Module</span>.<span class="property">runMain</span> = <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">//加载命令行中的第二个参数所指向的“test.js”模块</span></span><br><span class="line"> <span class="title class_">Module</span>.<span class="title function_">_load</span>(process.<span class="property">argv</span>[<span class="number">1</span>], <span class="literal">null</span>, <span class="literal">true</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="title class_">Module</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">load</span> = <span class="keyword">function</span>(<span class="params">filename</span>) {</span><br><span class="line"> <span class="comment">// 根据文件名的后缀调用具体的解析方式</span></span><br><span class="line"> <span class="title class_">Module</span>.<span class="property">_extensions</span>[extension](<span class="variable language_">this</span>, filename);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="title class_">Module</span>.<span class="property">_extensions</span>[<span class="string">'.js'</span>] = <span class="keyword">function</span>(<span class="params"><span class="variable language_">module</span>, filename</span>) {</span><br><span class="line"> <span class="keyword">var</span> content = fs.<span class="title function_">readFileSync</span>(filename, <span class="string">'utf8'</span>);</span><br><span class="line"> <span class="comment">// 在读取完内容js文件内容之后进行编译</span></span><br><span class="line"> <span class="variable language_">module</span>.<span class="title function_">_compile</span>(internalModule.<span class="title function_">stripBOM</span>(content), filename);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">以上三个方法只是解析 node test.js 这个命令,然后找到了 test.js 这个文件而已。</span></span><br><span class="line"><span class="comment">也就是对应着堆栈里面的:</span></span><br><span class="line"><span class="comment"> at Object.Module._extensions..js (module.js:405:10)</span></span><br><span class="line"><span class="comment"> at Module.load (module.js:344:32)</span></span><br><span class="line"><span class="comment"> at Function.Module._load (module.js:301:12)</span></span><br><span class="line"><span class="comment"> at Function.Module.runMain (module.js:430:10)</span></span><br><span class="line"><span class="comment"> at startup (node.js:141:18)</span></span><br><span class="line"><span class="comment"> at node.js:980:3</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">下面的_compile才是重点!</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">Module</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">_compile</span> = <span class="keyword">function</span>(<span class="params">content, filename</span>) {</span><br><span class="line"> .....</span><br><span class="line"> <span class="keyword">const</span> dirname = path.<span class="title function_">dirname</span>(filename);</span><br><span class="line"> <span class="keyword">const</span> <span class="built_in">require</span> = internalModule.<span class="property">makeRequireFunction</span>.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line"> <span class="comment">// 这里是重点!!!NodeJS在所有文件中的代码完成,都嵌套了一层。</span></span><br><span class="line"> <span class="keyword">const</span> args = [<span class="variable language_">this</span>.<span class="property">exports</span>, <span class="built_in">require</span>, <span class="variable language_">this</span>, filename, dirname];</span><br><span class="line"> <span class="keyword">return</span> compiledWrapper.<span class="title function_">apply</span>(<span class="variable language_">this</span>.<span class="property">exports</span>, args);</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="NodeJS的包裹层!"><a href="#NodeJS的包裹层!" class="headerlink" title="NodeJS的包裹层!"></a>NodeJS的包裹层!</h3><p>通过这个包裹层,我们原先的test.js文件就会变为下面这个样子。这也就是在我们写代码的时候,可以直接调用exports,require,module…的原因。</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></pre></td><td class="code"><pre><span class="line">(<span class="keyword">function</span>(<span class="params"><span class="built_in">exports</span>, <span class="built_in">require</span>, <span class="variable language_">module</span>, filename, dirname</span>)){</span><br><span class="line"> <span class="built_in">require</span>()</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ol><li>module<br>test.js会被解析为一个module。</li><li>exports<br>就是这个module上的一个属性。</li><li>require<br>调用require方法,最终调用的就是Module._load方法<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></pre></td><td class="code"><pre><span class="line"><span class="title class_">Module</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">require</span> = <span class="keyword">function</span>(<span class="params">path</span>) {</span><br><span class="line"> <span class="title function_">assert</span>(path, <span class="string">'missing path'</span>);</span><br><span class="line"> <span class="title function_">assert</span>(<span class="keyword">typeof</span> path === <span class="string">'string'</span>, <span class="string">'path must be a string'</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="title class_">Module</span>.<span class="title function_">_load</span>(path, <span class="variable language_">this</span>);</span><br><span class="line">};</span><br></pre></td></tr></table></figure></li></ol><h3 id="最终的那个异常"><a href="#最终的那个异常" class="headerlink" title="最终的那个异常"></a>最终的那个异常</h3><p>在require方法中,NodeJS会对参数进行检查。这也就是当我们最终执行test.js时,出现错误“AssertionError: missing path”的原因所在。</p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>所有加载完成的模块,都会缓存在require.cache上。当我们执行require操作的时候,NodeJS会先从缓存里面找,如果不存在,就会去找对应的文件进行编译。<br>这一个特性可以让我们做不少有趣的事情,比如:</p><ol><li>文件实时编译。<br>通过检测文件的改动,在发生改动时,清除require.cache缓存,对其进行重新加载编译。</li><li>动态的往exports上添加方法、属性。<br>因为exports是module对象上的属性,而module对象又是被缓存在require.cache上,所以也可以这样写。<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></pre></td><td class="code"><pre><span class="line"><span class="built_in">exports</span>.<span class="property">addMethod</span> = <span class="keyword">function</span>(<span class="params">methodName , method</span>){</span><br><span class="line"> <span class="built_in">exports</span>[methodName] = method</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>作为NodeJS的开发人员,想必都知道NodeJS主要通过require,exports这两个关键字将代码中的各个模块组合到一起。其中具体的机制,之前也大致看过,但是一直没有完整的整理过一遍。本文就从运行一个NodeJS脚本开始,把NodeJS加载脚本的过程梳理一遍,算是当作自己的笔记吧。</p></summary>
<category term="NodeJS" scheme="http://xtutu.github.io/categories/NodeJS/"/>
<category term="机制" scheme="http://xtutu.github.io/tags/%E6%9C%BA%E5%88%B6/"/>
<category term="原理" scheme="http://xtutu.github.io/tags/%E5%8E%9F%E7%90%86/"/>
<category term="依赖" scheme="http://xtutu.github.io/tags/%E4%BE%9D%E8%B5%96/"/>
</entry>
<entry>
<title>编写Hexo插件</title>
<link href="http://xtutu.github.io/write-hexo-plugin/"/>
<id>http://xtutu.github.io/write-hexo-plugin/</id>
<published>2015-12-20T02:00:00.000Z</published>
<updated>2023-05-24T08:46:04.937Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>Hexo已经用了大半年,真的很符合我写博客的种种需求。不过最近在使用Hexo中的skip_render标签时,遇到了一些问题。该标签下面的目录,还是会经过Hexo的处理,并不是我想像中的那样:直接把这些资源复制到public目录下面。<br>当我执行“hexo g”命令时,对于某些文件,Hexo中的nunjucks库会报错。于是就想着自己写一个复制资源的插件。(实际上对于这种比较简单的功能,通过写脚本来实现会更加方便)。看了下Hexo插件的实现机制,以及官方的文档之后,就简单的实验了下。下面就列举下过程。</p><span id="more"></span><h2 id="编写Hexo插件"><a href="#编写Hexo插件" class="headerlink" title="编写Hexo插件"></a>编写Hexo插件</h2><p>在官方手册里面可以看到Hexo是支持编写插件的,并且通过NPM来管理。而且官方的文档也写了不少关于编写插件的步骤,所以实现起来并不复杂。</p><h3 id="添加插件目录"><a href="#添加插件目录" class="headerlink" title="添加插件目录"></a>添加插件目录</h3><p><img src="/img/20151223165539.jpg" alt="这是一张图片"><br>在博客目录下的node_modules目录下,添加一个以hexo开头的目录,再在里面创建两个文件。</p><ol><li><p>index.js</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> hexo = hexo != <span class="literal">undefined</span> ? hexo : {}</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"test...1"</span>, __dirname)</span><br><span class="line">hexo.<span class="title function_">on</span>(<span class="string">"processAfter"</span>, <span class="keyword">function</span>(<span class="params"></span>){</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"test...2"</span>, __dirname)</span><br><span class="line">})</span><br></pre></td></tr></table></figure></li><li><p>package.json</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></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="string">"name"</span>: <span class="string">"hexo-just-copy"</span>,</span><br><span class="line"> <span class="string">"version"</span>: <span class="string">"0.0.1"</span>,</span><br><span class="line"> <span class="string">"main"</span>: <span class="string">"index"</span></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li></ol><h3 id="编辑博客目录下的package-json文件"><a href="#编辑博客目录下的package-json文件" class="headerlink" title="编辑博客目录下的package.json文件"></a>编辑博客目录下的package.json文件</h3><p>在字段dependencies中添加:</p><blockquote><p>“hexo-just-copy” : “^0.0.1”</p></blockquote><h3 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h3><p><img src="/img/20151223175052.jpg"></p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>更多功能可以参考node_modules目录下其它插件的写法。<br>以及官方文档:<br><a href="https://hexo.io/docs/plugins.html">https://hexo.io/docs/plugins.html</a><br><a href="https://hexo.io/api/events.html">https://hexo.io/api/events.html</a></p><p>最后附上一个执行复制的python脚本。。。毕竟还是写脚本方便。</p><figure class="highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> shutil </span><br><span class="line"></span><br><span class="line">currentPath = os.path.realpath(__file__)</span><br><span class="line">currentPath = os.path.dirname(currentPath)</span><br><span class="line"><span class="built_in">print</span> (currentPath)</span><br><span class="line">dstDir = currentPath + <span class="string">"\\public\\game"</span></span><br><span class="line">srcDir = currentPath + <span class="string">"\\copyDate"</span></span><br><span class="line"><span class="comment"># print dstDir</span></span><br><span class="line"></span><br><span class="line">cmd = os.popen(<span class="string">"hexo clean"</span>)</span><br><span class="line">cmdInfo = cmd.read()</span><br><span class="line"><span class="built_in">print</span> cmdInfo</span><br><span class="line"></span><br><span class="line">cmd = os.popen(<span class="string">"hexo g"</span>)</span><br><span class="line">cmdInfo = cmd.read()</span><br><span class="line"><span class="built_in">print</span> cmdInfo</span><br><span class="line"></span><br><span class="line">shutil.copytree(srcDir,dstDir) </span><br><span class="line"></span><br><span class="line">cmd = os.popen(<span class="string">"hexo d"</span>)</span><br><span class="line">cmdInfo = cmd.read()</span><br><span class="line"><span class="built_in">print</span> cmdInfo </span><br><span class="line"></span><br><span class="line">raw_input(<span class="string">"Press ENTER to exit"</span>)</span><br></pre></td></tr></table></figure><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>Hexo已经用了大半年,真的很符合我写博客的种种需求。不过最近在使用Hexo中的skip_render标签时,遇到了一些问题。该标签下面的目录,还是会经过Hexo的处理,并不是我想像中的那样:直接把这些资源复制到public目录下面。<br>当我执行“hexo g”命令时,对于某些文件,Hexo中的nunjucks库会报错。于是就想着自己写一个复制资源的插件。(实际上对于这种比较简单的功能,通过写脚本来实现会更加方便)。看了下Hexo插件的实现机制,以及官方的文档之后,就简单的实验了下。下面就列举下过程。</p></summary>
<category term="Hexo" scheme="http://xtutu.github.io/categories/Hexo/"/>
<category term="Hexo" scheme="http://xtutu.github.io/tags/Hexo/"/>
<category term="Plugins" scheme="http://xtutu.github.io/tags/Plugins/"/>
<category term="分析" scheme="http://xtutu.github.io/tags/%E5%88%86%E6%9E%90/"/>
</entry>
<entry>
<title>只有Google才能搜索到我的网站?!</title>
<link href="http://xtutu.github.io/search-engine-and-my-website/"/>
<id>http://xtutu.github.io/search-engine-and-my-website/</id>
<published>2015-12-11T22:00:00.000Z</published>
<updated>2016-02-24T02:00:00.000Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>博客已经写了一段时间,这几天看到小伙伴在群上贴了一张图,大体是关于:在Google搜索某个关键字,可以在前几条记录里面找到他的博客内容。于是我抱着试一试的心态,在Google上搜了下自己博客里的一些关键字,效果出乎意料的好!但当我用百度,好搜,神马之类的国内搜索引擎,搜索同样的关键字,却几乎看不到任何博客信息。</p><span id="more"></span><h2 id="Google搜索效果"><a href="#Google搜索效果" class="headerlink" title="Google搜索效果"></a>Google搜索效果</h2><p>搜索以下几个关键字,都可以在前面几条可以找到我的博客!</p><h3 id="搜索”xtutu”"><a href="#搜索”xtutu”" class="headerlink" title="搜索”xtutu”"></a>搜索”xtutu”</h3><p><img src="/img/g20151211152712.png" alt="这是一张图片"></p><h3 id="搜索”游戏产品-客户端”"><a href="#搜索”游戏产品-客户端”" class="headerlink" title="搜索”游戏产品 客户端”"></a>搜索”游戏产品 客户端”</h3><p><img src="/img/g20151211152919.png" alt="这是一张图片"></p><h3 id="搜索”游戏-转盘-算法”"><a href="#搜索”游戏-转盘-算法”" class="headerlink" title="搜索”游戏 转盘 算法”"></a>搜索”游戏 转盘 算法”</h3><p><img src="/img/g20151211153030.png" alt="这是一张图片"></p><h3 id="搜索”服务端架构-思考”"><a href="#搜索”服务端架构-思考”" class="headerlink" title="搜索”服务端架构 思考”"></a>搜索”服务端架构 思考”</h3><p><img src="/img/g20151211153107.png" alt="这是一张图片"></p><h3 id="搜索”c-添加-lua”"><a href="#搜索”c-添加-lua”" class="headerlink" title="搜索”c++ 添加 lua”"></a>搜索”c++ 添加 lua”</h3><p><img src="/img/g20151214180240.png" alt="这是一张图片"></p><h2 id="手动提交sitemap"><a href="#手动提交sitemap" class="headerlink" title="手动提交sitemap"></a>手动提交sitemap</h2><p>毕竟在国内,百度的用户还是不少的。<br>既然百度无法主动搜索到我的网站,只能靠我们自己把网站信息手动提交给百度了!<br><a href="http://zhanzhang.baidu.com/dashboard/index">地址</a><br>同理,好搜,神马搜索都可以自己手动来提交网站的sitemap。</p><h2 id="但是!!!"><a href="#但是!!!" class="headerlink" title="但是!!!"></a>但是!!!</h2><p>然后百度居然不支持hexo的sitemap!!!</p><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><p>好在百度还支持主动推送,所以只好自己写脚本把网站的sitemap.xml解析成百度支持的格式,然后再发给ta。<br>代码如下,注意配置这块改成自己的。自己的信息可以从这里找到,就是图中的接口调用地址。<br><img src="/img/20160129102059.jpg" alt="pic"></p><figure class="highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># !/usr/bin/env python</span></span><br><span class="line"><span class="comment"># coding=utf8</span></span><br><span class="line"><span class="keyword">import</span> urllib2</span><br><span class="line"><span class="keyword">import</span> urllib</span><br><span class="line"><span class="keyword">from</span> xml.dom <span class="keyword">import</span> minidom</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_nodevalue</span>(<span class="params">node, index = <span class="number">0</span></span>):</span><br><span class="line"> <span class="keyword">return</span> node.childNodes[index].nodeValue <span class="keyword">if</span> node <span class="keyword">else</span> <span class="string">''</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置信息</span></span><br><span class="line"><span class="comment"># 如果sitemap中的地址是xtutu.me,当设为True的时候,就会自动把地址补为www.xtutu.me</span></span><br><span class="line">needAddWWW = <span class="literal">False</span> </span><br><span class="line">sitemapUrl = <span class="string">"http://xtutu.github.io/sitemap.xml"</span></span><br><span class="line"><span class="comment"># token位置,比如我的网站是在这里查看</span></span><br><span class="line"><span class="comment"># http://zhanzhang.baidu.com/linksubmit/index?site=http://xtutu.github.io/</span></span><br><span class="line">baiduUrl = <span class="string">"http://data.zz.baidu.com/urls?site=www.xtutu.me&token=xxxxxxxxxxxxxxxx"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取并解析xml文件</span></span><br><span class="line">linksStr = <span class="string">""</span></span><br><span class="line">req = urllib2.urlopen(sitemapUrl)</span><br><span class="line">xmlVal = req.read()</span><br><span class="line">doc = minidom.parseString(xmlVal)</span><br><span class="line">root = doc.documentElement</span><br><span class="line">urlSet = root.getElementsByTagName(<span class="string">'url'</span>)</span><br><span class="line"><span class="keyword">for</span> node <span class="keyword">in</span> urlSet:</span><br><span class="line"> urlString = get_nodevalue(node.getElementsByTagName(<span class="string">'loc'</span>)[<span class="number">0</span>]).encode(<span class="string">'utf-8'</span>,<span class="string">'ignore'</span>)</span><br><span class="line"> <span class="keyword">if</span> needAddWWW: <span class="comment"># 判断是否需添加www字段</span></span><br><span class="line"> urlString = urlString.replace(<span class="string">"://"</span>, <span class="string">"://www."</span>)</span><br><span class="line"> linksStr = linksStr + urlString + <span class="string">"\n"</span></span><br><span class="line"><span class="built_in">print</span> linksStr</span><br><span class="line"></span><br><span class="line"><span class="comment"># 发送xml文件给百度</span></span><br><span class="line">req = urllib2.urlopen(baiduUrl, linksStr)</span><br><span class="line">content = req.read()</span><br><span class="line"><span class="built_in">print</span> content</span><br><span class="line"></span><br><span class="line">raw_input(<span class="string">"Press ENTER to exit"</span>)</span><br></pre></td></tr></table></figure><p>输出结果</p><figure class="highlight python"><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></pre></td><td class="code"><pre><span class="line">http://xtutu.github.io/search-engine-<span class="keyword">and</span>-my-website/</span><br><span class="line">http://xtutu.github.io/baidu_verify_4Lm08kj7TJ.html</span><br><span class="line">http://xtutu.github.io/egret-graphics-draw-optimize/</span><br><span class="line">http://xtutu.github.io/game-wheel-lottery/</span><br><span class="line">http://xtutu.github.io/think-about-server/</span><br><span class="line">http://xtutu.github.io/helloworld/</span><br><span class="line">http://xtutu.github.io/typescript-javascript-compare/</span><br><span class="line">http://xtutu.github.io/egret-source-part-mainloop/</span><br><span class="line">http://xtutu.github.io/egret-source-part-render/</span><br><span class="line">http://xtutu.github.io/how-to-create-a-good-game-<span class="keyword">for</span>-client-programmer/</span><br><span class="line">http://xtutu.github.io/python-script-to-upload-directory-<span class="keyword">from</span>-windows-to-a-linux-server-achieving-one-click-deployment/</span><br><span class="line">http://xtutu.github.io/the-date-<span class="built_in">object</span>-<span class="keyword">in</span>-js/</span><br><span class="line">http://xtutu.github.io/coffeescript-javascript-compare/</span><br><span class="line">http://xtutu.github.io/add-lua-support-<span class="keyword">for</span>-cplusplus-project/</span><br><span class="line">http://xtutu.github.io/categories/index.html</span><br><span class="line">http://xtutu.github.io/tags/index.html</span><br><span class="line">http://xtutu.github.io/egret/</span><br><span class="line">http://xtutu.github.io/about/index.html</span><br><span class="line">http://xtutu.github.io/<span class="number">404.</span>html</span><br><span class="line"></span><br><span class="line">{<span class="string">"remain"</span>:<span class="number">387</span>,<span class="string">"success"</span>:<span class="number">19</span>}</span><br></pre></td></tr></table></figure><p><strong>百度,我只能帮你到这里了</strong></p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>好搜,神马在提交了sitemap之后,搜索结果的确是有了不少改善,但是还是没有google那么精准。<br>至于百度。。。搜索结果依旧毫无改善。<br>查了下资料,才发现居然是因为Github主动屏蔽了来自于BaiduSpider的请求。- -!<br>不过这一情况可以通过CDN(国内的很多平台都需要备案)来解决,可以参考以下这篇文章:<br><a href="http://www.dozer.cc/2015/06/github-pages-and-cdn.html">http://www.dozer.cc/2015/06/github-pages-and-cdn.html</a><br>目前我是把博客移到了gitcafe上。。。但是即使我做了这么多,百度依旧搜不到我的博客,看来只能慢慢等百度收录了。。。</p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>博客已经写了一段时间,这几天看到小伙伴在群上贴了一张图,大体是关于:在Google搜索某个关键字,可以在前几条记录里面找到他的博客内容。于是我抱着试一试的心态,在Google上搜了下自己博客里的一些关键字,效果出乎意料的好!但当我用百度,好搜,神马之类的国内搜索引擎,搜索同样的关键字,却几乎看不到任何博客信息。</p></summary>
<category term="长知识" scheme="http://xtutu.github.io/categories/%E9%95%BF%E7%9F%A5%E8%AF%86/"/>
<category term="搜索引擎" scheme="http://xtutu.github.io/tags/%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E/"/>
<category term="关键字" scheme="http://xtutu.github.io/tags/%E5%85%B3%E9%94%AE%E5%AD%97/"/>
<category term="排名" scheme="http://xtutu.github.io/tags/%E6%8E%92%E5%90%8D/"/>
<category term="Baidu" scheme="http://xtutu.github.io/tags/Baidu/"/>
</entry>
<entry>
<title>服务端架构的一些思考</title>
<link href="http://xtutu.github.io/think-about-server/"/>
<id>http://xtutu.github.io/think-about-server/</id>
<published>2015-10-25T10:00:00.000Z</published>
<updated>2023-05-24T08:46:04.935Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>自从做了服务端开发之后,也算是把自己的一块空白补全了。之前对服务端的了解,主要是Socket通讯这一块,毕竟游戏客户端和服务端的通讯接口是类似的(之前做的是Socket长连接的手游)。虽然自己也看过项目组服务端的代码,但终归没有机会专心的去做服务端的开发。<br>目前做服务端开发已经有3个多月了,结合自己之前的理解,差不多把这几年的所学、所用的东西都贯穿了起来。几年前比较模糊的概念、架构,现在都看的比较特彻了。</p><span id="more"></span><h2 id="关于目前"><a href="#关于目前" class="headerlink" title="关于目前"></a>关于目前</h2><p>目前在开发的产品的一些功能和微信比较接近,用的是Nodejs的Express来开发,采用http来通讯,mongodb作为数据库。</p><hr><h2 id="服务端的架构"><a href="#服务端的架构" class="headerlink" title="服务端的架构"></a>服务端的架构</h2><h3 id="之前所开发的手游服务端架构"><a href="#之前所开发的手游服务端架构" class="headerlink" title="之前所开发的手游服务端架构"></a>之前所开发的手游服务端架构</h3><p>当时采用的是socket长连接来通讯,因为没有用第三方现有的服务端框架,所以底层socket的封装,以及协议内容的定义都是从0开始写。比如通讯协议定的数据格式是最原始二进制,每个协议发的二进制内容大体由“数据长度+操作码+具体内容”组成。服务端结构如下:</p><ul><li>一台登入服务器</li><li>多台逻辑服务器(一个区一个服务器)</li></ul><p>客户端通过连接登入服务器验证账户,再连接具体的游戏逻辑服务器。现在许多游戏都是这种登入服务器与逻辑服务器分开的架构:</p><blockquote><p>英雄联盟:如果长时间在选区界面不动,就会被踢下线。<br>炉石传说:记得当时暗黑3刚开放的那天晚上,炉石传说都挤得无法登入了。估计他们两游戏用的是同一台登入服务器。</p></blockquote><h3 id="当前NodeJS服务端的架构"><a href="#当前NodeJS服务端的架构" class="headerlink" title="当前NodeJS服务端的架构"></a>当前NodeJS服务端的架构</h3><p>因为是http通讯,所以服务端对于手机客户端来说,差不多就是提供一套RESTful API。这里之所以只说手机客户端,是因为目前的服务端还负责网页这一块的显示,其实也是可以完全把网页端当作一个客户端来开发,服务端只负责提供通讯接口。比如借助一些MVVM的框架,把前端的显示和数据,完全分离开来。我试着用过avalon来写一个网页工具,来调试服务端的通讯协议,效果还是蛮不错的。服务端结构如下:</p><ul><li>登入服务器</li><li>逻辑服务器</li><li>文件服务器</li></ul><h3 id="负载均衡"><a href="#负载均衡" class="headerlink" title="负载均衡"></a>负载均衡</h3><p>以上两种架构,都会遇到性能上的瓶颈。</p><ul><li>手游服务端:当时的负载量差不多是同时在线1000人,压力就比较大了(不过当时的服务器配置也不算太高)。 <blockquote><p>解决方案就是开新服,一是技术实现上比较简单,二是,开新服可以获得更多的新用户。</p></blockquote></li><li>NodeJS服务端:因为所有用户是算在一个区,所以总用户量会非常大,目前遇到的主要瓶颈是带宽不够用。 <blockquote><p>Http通讯协议的确是比较费流量,多余的报头、再加上是用json作为协议格式、以及post传参格式的多种多样,这和用纯socket传二进制数据流是完全不能比的。<br>不过http也有它的优势:<strong>无状态</strong>。<br>所以对http结构做负载均衡比较方便,只需要多开几台逻辑服务器,这些服务器通过连接同一个数据库,再加上一个管理服务器来把请求分发给各个逻辑服务器就可以了。</p></blockquote></li></ul><h3 id="数据库的压力"><a href="#数据库的压力" class="headerlink" title="数据库的压力"></a>数据库的压力</h3><p>以上的负载均衡主要是针对带宽,CPU之类的性能瓶颈。对于不分区的App应用来说,还有一个比较大的瓶颈就是数据库这块。这一块内容之后再专门写一篇文章! (更新: *<a href="/technology-is-not-threshold-any-more">《技术正变得不再是门槛》</a> * )</p><h2 id="Pomelo!!!"><a href="#Pomelo!!!" class="headerlink" title="Pomelo!!!"></a>Pomelo!!!</h2><p>前段时间,看了下网易的开源引擎<a href="http://pomelo.netease.com/index.html">Pomelo</a>,的确是开阔了下思路。它的实现机制有点把前面两种服务端架构结合了起来的味道。</p><h3 id="Gate"><a href="#Gate" class="headerlink" title="Gate"></a>Gate</h3><p>相当于之前手游服务端里面的登入服务器</p><h3 id="Connector和具体的逻辑服务器"><a href="#Connector和具体的逻辑服务器" class="headerlink" title="Connector和具体的逻辑服务器"></a>Connector和具体的逻辑服务器</h3><p>类似http服务端里面的那个负载均衡的管理服务器和具体的逻辑服务器。</p><blockquote><p>当你在用手机QQ语音的时候,可以无缝切换到用iPad上进行语音聊天。通过这种先连接connector,再通过connector来连接具体的逻辑服务器的机制,可以很方便的实现这种效果。</p></blockquote><h3 id="其它"><a href="#其它" class="headerlink" title="其它"></a>其它</h3><p>还有路由系统,channel机制,rpc机制等等…都很有亮点!有点相见恨晚的感觉,有空的时候,一定好好看下!</p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>自从做了服务端开发之后,也算是把自己的一块空白补全了。之前对服务端的了解,主要是Socket通讯这一块,毕竟游戏客户端和服务端的通讯接口是类似的(之前做的是Socket长连接的手游)。虽然自己也看过项目组服务端的代码,但终归没有机会专心的去做服务端的开发。<br>目前做服务端开发已经有3个多月了,结合自己之前的理解,差不多把这几年的所学、所用的东西都贯穿了起来。几年前比较模糊的概念、架构,现在都看的比较特彻了。</p></summary>
<category term="小结" scheme="http://xtutu.github.io/categories/%E5%B0%8F%E7%BB%93/"/>
<category term="Server" scheme="http://xtutu.github.io/tags/Server/"/>
<category term="总结" scheme="http://xtutu.github.io/tags/%E6%80%BB%E7%BB%93/"/>
</entry>
<entry>
<title>JavaScript中的Date对象,以及UTC、GMT、时区的关系</title>
<link href="http://xtutu.github.io/the-date-object-in-js/"/>
<id>http://xtutu.github.io/the-date-object-in-js/</id>
<published>2015-10-01T10:00:00.000Z</published>
<updated>2023-05-24T08:46:04.935Z</updated>
<content type="html"><![CDATA[<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>最近在写一个功能的时候,需要把本地时间0点的时间戳存下来。因为一直就没怎么去研究UTC、GMT、本地时间(中国算是东八区)的关系,所以乘着要写这个功能,就把这几个概念理了一下。</p><span id="more"></span><h2 id="UTC与GMT的关系"><a href="#UTC与GMT的关系" class="headerlink" title="UTC与GMT的关系"></a>UTC与GMT的关系</h2><p>UTC和GMT实际上可以理解为同一东西,具体的关系如下。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable constant_">UTC</span> = <span class="variable constant_">GMT</span> +/- <span class="number">0.9</span> s</span><br></pre></td></tr></table></figure><p>我们国家的时间实际是UTC+8,也就是说当国际标准时间为1号早上8点的时候,我们的本地时间是1号的16点。<br>即:东八区比标准时间快8小时。</p><h2 id="JS中Date对象主要方法所用的参数,以及返回类型"><a href="#JS中Date对象主要方法所用的参数,以及返回类型" class="headerlink" title="JS中Date对象主要方法所用的参数,以及返回类型"></a>JS中Date对象主要方法所用的参数,以及返回类型</h2><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 该方法传递的是国际标准时间</span></span><br><span class="line">now = <span class="keyword">new</span> <span class="title class_">Date</span>(int) </span><br><span class="line"></span><br><span class="line"><span class="comment">// 该方法返回的也是国际标准时间戳</span></span><br><span class="line"><span class="title function_">getTime</span>()返回 国际时间 <span class="number">1970</span> 年 <span class="number">1</span> 月 <span class="number">1</span> 日 <span class="number">0</span>点至今的毫秒数。(也就是我们东八区的<span class="number">1970</span> 年 <span class="number">1</span> 月 <span class="number">1</span> 日 <span class="number">8</span>点至今的毫秒数)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 以下方法返回的是本地时间</span></span><br><span class="line"><span class="title function_">getDate</span>()从 <span class="title class_">Date</span> 对象返回一个月中的某一天 (<span class="number">1</span> ~ <span class="number">31</span>)。本地时间</span><br><span class="line"><span class="title function_">getDay</span>()从 <span class="title class_">Date</span> 对象返回一周中的某一天 (<span class="number">0</span> ~ <span class="number">6</span>)。本地时间</span><br><span class="line"><span class="title function_">getMonth</span>()从 <span class="title class_">Date</span> 对象返回月份 (<span class="number">0</span> ~ <span class="number">11</span>)。本地时间</span><br><span class="line"><span class="title function_">getFullYear</span>()从 <span class="title class_">Date</span> 对象以四位数字返回年份。本地时间</span><br><span class="line"><span class="title function_">getYear</span>()请使用 <span class="title function_">getFullYear</span>() 方法代替。本地时间</span><br><span class="line"><span class="title function_">getHours</span>()返回 <span class="title class_">Date</span> 对象的小时 (<span class="number">0</span> ~ <span class="number">23</span>)。本地时间</span><br><span class="line"><span class="title function_">getMinutes</span>()返回 <span class="title class_">Date</span> 对象的分钟 (<span class="number">0</span> ~ <span class="number">59</span>)。本地时间</span><br><span class="line"><span class="title function_">getSeconds</span>()返回 <span class="title class_">Date</span> 对象的秒数 (<span class="number">0</span> ~ <span class="number">59</span>)。本地时间</span><br><span class="line"><span class="title function_">getMilliseconds</span>() 返回 <span class="title class_">Date</span> 对象的毫秒(<span class="number">0</span> ~ <span class="number">999</span>)。本地时间</span><br><span class="line"></span><br><span class="line"><span class="comment">// 以下方法返回的是国际标准时间</span></span><br><span class="line"><span class="title function_">getUTCDate</span>()根据世界时从 <span class="title class_">Date</span> 对象返回月中的一天 (<span class="number">1</span> ~ <span class="number">31</span>)。国际标准时间</span><br><span class="line"><span class="title function_">getUTCDay</span>()根据世界时从 <span class="title class_">Date</span> 对象返回周中的一天 (<span class="number">0</span> ~ <span class="number">6</span>)。国际标准时间</span><br><span class="line"><span class="title function_">getUTCMonth</span>()根据世界时从 <span class="title class_">Date</span> 对象返回月份 (<span class="number">0</span> ~ <span class="number">11</span>)。国际标准时间</span><br><span class="line"><span class="title function_">getUTCFullYear</span>()根据世界时从 <span class="title class_">Date</span> 对象返回四位数的年份。国际标准时间</span><br><span class="line"><span class="title function_">getUTCHours</span>()根据世界时返回 <span class="title class_">Date</span> 对象的小时 (<span class="number">0</span> ~ <span class="number">23</span>)。国际标准时间</span><br><span class="line"><span class="title function_">getUTCMinutes</span>()根据世界时返回 <span class="title class_">Date</span> 对象的分钟 (<span class="number">0</span> ~ <span class="number">59</span>)。国际标准时间</span><br><span class="line"><span class="title function_">getUTCSeconds</span>()根据世界时返回 <span class="title class_">Date</span> 对象的秒钟 (<span class="number">0</span> ~ <span class="number">59</span>)。国际标准时间</span><br><span class="line"><span class="title function_">getUTCMilliseconds</span>() 根据世界时返回 <span class="title class_">Date</span> 对象的毫秒(<span class="number">0</span> ~ <span class="number">999</span>)。国际标准时间</span><br><span class="line"></span><br><span class="line"><span class="comment">// 以下两个方法返回本地时间的字符串</span></span><br><span class="line"><span class="title function_">toLocaleString</span>()</span><br><span class="line"><span class="title function_">toString</span>()</span><br><span class="line"></span><br><span class="line"><span class="comment">// 返回国际标准时间的字符串</span></span><br><span class="line"><span class="title function_">toUTCString</span>()</span><br></pre></td></tr></table></figure><p>从上面的api中可以看到Date中的,getTime方比较特殊,它虽然没有加UTC这个标识,但是实际上返回的却是UTC的时间戳,估计主要是为了和构造方法对应起来。</p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>理清这些概念之后,实现起来就比较清晰了。最后附上获取本地当天0点时间的国际标准时间戳(有点绕口…)</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="built_in">exports</span>.<span class="property">getZeroTime</span> =()-></span><br><span class="line"> now = <span class="keyword">new</span> <span class="title class_">Date</span>()</span><br><span class="line"> now.<span class="title function_">setHours</span>(<span class="number">0</span>);now.<span class="title function_">setMinutes</span>(<span class="number">0</span>); now.<span class="title function_">setSeconds</span>(<span class="number">0</span>); now.<span class="title function_">setMilliseconds</span>(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">return</span> now.<span class="title function_">getTime</span>()</span><br></pre></td></tr></table></figure><h2 id="更进一步"><a href="#更进一步" class="headerlink" title="更进一步"></a>更进一步</h2><p>在本文开头提到了需要把本地时间0点的时间戳存下来。那么如果现在要做一个功能,是记录全球所有用户每天的体温变化。那么是存各地区本地的0点时间的时间戳方便,还是存国际标准0点时间的时间戳方便呢?<br><strong>(存数据库里面的时间戳都是国际时间 1970 年 1 月 1 日 0点至今的毫秒数</strong>)。<br><strong>以下内容没有具体实验,纯理论分析,如果有问题,请给我留言;-)</strong></p><h3 id="如果存本地0点时间"><a href="#如果存本地0点时间" class="headerlink" title="如果存本地0点时间"></a>如果存本地0点时间</h3><blockquote><p> 因为存的是本地时间,所以每个地区的时间数据都是不统一的。以本地时间10月24号为例,西时区:存的就是10月24号国际标准时间戳+0<del>12小时;东时区存的就是10月24号国际标准时间戳-(0</del>12)小时,也就是10月23号的国际标准时间戳+(12~24)小时。</p></blockquote><ol><li>**查询全球所有用户国际标准时间(比如说是10月24号)的数据 **<br>查询条件为10月24号0点国际标准时间+/-12小时内。 其中西时区为+0<del>12,东时区为-12</del>0</li><li><strong>查询全球所有用户本地时间(比如说是10月24号)的数据</strong><br>查询条件为10月24号0点国际标准时间+24小时内。其中西时区为+0<del>12,东时区为12</del>24</li></ol><h3 id="如果存国际标准0点时间"><a href="#如果存国际标准0点时间" class="headerlink" title="如果存国际标准0点时间"></a>如果存国际标准0点时间</h3><blockquote><p> 以本地时间10月24号为例,不管是西时区还是东时区存的都是10月24号国际标准时间戳。</p></blockquote><ol><li><strong>查询全球所有用户国际标准时间(比如说是10月24号)的数据</strong><br>直接查就是了,没有什么问题</li><li><strong>查询全球所有用户本地时间(比如说是10月24号)的数据</strong><br>查询条件为10月24号0点国际标准时间+/-12小时内。 其中西时区为+0<del>12,东时区为-12</del>0</li></ol><hr><p>最后结合项目的实际需求,就可以选择最合适的存储格式了。</p><hr><p><strong>更新2016-4-10</strong><br>最近很火的手游《皇室战争》,采用的就是<strong>国际标准0点时间</strong>作为一天的开始。<br>具体表现为:<strong>中国区部落的捐赠数量会在每个星期一的早上8点清零!</strong></p><blockquote><p>转载本站文章请注明作者(xtutu)和出处 <a href="http://xtutu.github.io/">xtutu</a></p></blockquote>]]></content>
<summary type="html"><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>最近在写一个功能的时候,需要把本地时间0点的时间戳存下来。因为一直就没怎么去研究UTC、GMT、本地时间(中国算是东八区)的关系,所以乘着要写这个功能,就把这几个概念理了一下。</p></summary>
<category term="JavaScript" scheme="http://xtutu.github.io/categories/JavaScript/"/>
<category term="Date" scheme="http://xtutu.github.io/tags/Date/"/>
<category term="UTC" scheme="http://xtutu.github.io/tags/UTC/"/>
<category term="GMT" scheme="http://xtutu.github.io/tags/GMT/"/>
</entry>
</feed>