-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathatom.xml
683 lines (455 loc) · 165 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
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
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>前端志</title>
<link href="/atom.xml" rel="self"/>
<link href="http://hushicai.github.io/"/>
<updated>2018-07-06T18:18:49.000Z</updated>
<id>http://hushicai.github.io/</id>
<author>
<name>hushicai</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>让vim支持`+clipboard`</title>
<link href="http://hushicai.github.io/2016/01/08/rang-vim-zhi-chi-clipboard.html"/>
<id>http://hushicai.github.io/2016/01/08/rang-vim-zhi-chi-clipboard.html</id>
<published>2016-01-07T17:20:40.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>ubuntu中系统默认的vim真是折腾,竟然不支持<code>+clipboard</code>.</p><p>如果没有开启clipboard特性,那vim就没法和系统的粘贴板交互,也就是说我们用<code>"+y</code>命令复制之后,没办法粘贴到其他地方,比如浏览器等.</p><p><code>vim-gnome</code>这个包给vim提供了<code>+clipboard</code>特性.我们只需要安装一下就可以了.</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install vim-gnome</span><br></pre></td></tr></table></figure><p>然后再查看一下,应该已经成功开启了:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim --version | grep clipboard</span><br></pre></td></tr></table></figure><h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><ul><li><a href="http://vimcasts.org/blog/2013/11/getting-vim-with-clipboard-support/" target="_blank" rel="noopener">http://vimcasts.org/blog/2013/11/getting-vim-with-clipboard-support/</a></li></ul>]]></content>
<summary type="html">
<p>ubuntu中系统默认的vim真是折腾,竟然不支持<code>+clipboard</code>.</p>
<p>如果没有开启clipboard特性,那vim就没法和系统的粘贴板交互,也就是说我们用<code>&quot;+y</code>命令复制之后,没办法粘贴到其他地方
</summary>
<category term="vim" scheme="http://hushicai.github.io/tags/vim/"/>
<category term="clipboard" scheme="http://hushicai.github.io/tags/clipboard/"/>
</entry>
<entry>
<title>ls目录颜色</title>
<link href="http://hushicai.github.io/2016/01/08/ls-mu-lu-yan-se.html"/>
<id>http://hushicai.github.io/2016/01/08/ls-mu-lu-yan-se.html</id>
<published>2016-01-07T16:52:43.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>最近在折腾ubuntu,又是各种配置…</p><p>首先要把terminal给搞定了,其中一项就是ls的颜色问题.</p><p>无意中发现了一个挺不错的repo: <a href="https://github.com/seebi/dircolors-solarized" target="_blank" rel="noopener">dircolors-solarized</a>,这货是基于<code>solarized</code>的颜色方案,很不错,严重推荐!</p><p>安装方法很简单,照上面的方法操作即可.</p><p>再也不用找度娘了,哈哈!</p>]]></content>
<summary type="html">
<p>最近在折腾ubuntu,又是各种配置…</p>
<p>首先要把terminal给搞定了,其中一项就是ls的颜色问题.</p>
<p>无意中发现了一个挺不错的repo: <a href="https://github.com/seebi/dircolors-solarized
</summary>
<category term="ls" scheme="http://hushicai.github.io/tags/ls/"/>
<category term="ubuntu" scheme="http://hushicai.github.io/tags/ubuntu/"/>
<category term="lscolors" scheme="http://hushicai.github.io/tags/lscolors/"/>
<category term="dircolors" scheme="http://hushicai.github.io/tags/dircolors/"/>
</entry>
<entry>
<title>win7将CapsLock映射为Ctrl</title>
<link href="http://hushicai.github.io/2016/01/07/win7-jiang-CapsLock-ying-she-wei-Ctrl.html"/>
<id>http://hushicai.github.io/2016/01/07/win7-jiang-CapsLock-ying-she-wei-Ctrl.html</id>
<published>2016-01-07T15:52:13.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>从狼厂离职之后,没有了mac,一直在用windows系统,以sublime作为开发工具.</p><p>最近实在受不了,装了个ubuntu虚拟机,回到vim.(暂时还不想买mac…)</p><p>作为一个vim党,快速移动手指很重要,很显然,键盘上的CapsLock键实在是太浪费了,必须把它搞成Ctrl键.</p><p>这有个windows注册文件,内容如下:</p><figure class="highlight plain"><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">Windows Registry Editor Version 5.00</span><br><span class="line"></span><br><span class="line">[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]</span><br><span class="line">"Scancode Map"=hex:00,00,00,00,00,00,00,00,02,00,00,00,1d,00,3a,00,00,00,00,00</span><br></pre></td></tr></table></figure><p>将以上内容保存到一个reg文件中,比如<code>caps_lock_to_ctrl.reg</code>,双击注册到windows注册表,然后重启电脑即可.</p><h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><ul><li><a href="http://johnhaller.com/useful-stuff/disable-caps-lock" target="_blank" rel="noopener">http://johnhaller.com/useful-stuff/disable-caps-lock</a></li><li><a href="http://vim.wikia.com/wiki/Map_caps_lock_to_escape_in_Windows#Use_the_Caps_Lock_key_as_Ctrl" target="_blank" rel="noopener">http://vim.wikia.com/wiki/Map_caps_lock_to_escape_in_Windows#Use_the_Caps_Lock_key_as_Ctrl</a></li></ul>]]></content>
<summary type="html">
<p>从狼厂离职之后,没有了mac,一直在用windows系统,以sublime作为开发工具.</p>
<p>最近实在受不了,装了个ubuntu虚拟机,回到vim.(暂时还不想买mac…)</p>
<p>作为一个vim党,快速移动手指很重要,很显然,键盘上的CapsLock键实在
</summary>
<category term="windows" scheme="http://hushicai.github.io/tags/windows/"/>
<category term="Caps Lock" scheme="http://hushicai.github.io/tags/Caps-Lock/"/>
<category term="Ctrl" scheme="http://hushicai.github.io/tags/Ctrl/"/>
</entry>
<entry>
<title>让python在交互模式下支持tab completion</title>
<link href="http://hushicai.github.io/2015/10/09/python-interative-mode-tab-completion.html"/>
<id>http://hushicai.github.io/2015/10/09/python-interative-mode-tab-completion.html</id>
<published>2015-10-09T09:12:29.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>本人使用的是mac os x 10.10.5版本,shell是zsh。</p><p>zsh的自定义配置在~/.oh-my-zsh/custom/my.zsh中。</p><p>首先在<code>~/.oh-my-zsh/custom/my.zsh</code>中配置如下:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> PYTHONSTARTUP=<span class="variable">$HOME</span>/.pythonrc.py</span><br></pre></td></tr></table></figure><p><em>Note:如果你的zsh没有自定义配置文件,你可以直接在<code>~/.zshrc</code>配置。</em></p><a id="more"></a><p>然后在个人主目录下新建一个<code>~/.pythonrc.py</code>z文件:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span>:</span><br><span class="line"> <span class="keyword">import</span> readline</span><br><span class="line"><span class="keyword">except</span> ImportError:</span><br><span class="line"> print(<span class="string">"Module readline not available."</span>)</span><br><span class="line"><span class="keyword">else</span>:</span><br><span class="line"> <span class="keyword">import</span> rlcompleter</span><br><span class="line"> readline.parse_and_bind(<span class="string">"tab: complete"</span>)</span><br></pre></td></tr></table></figure><p>新开一个ternimal窗口,让以上配置生效即可。</p><p>效果如下:</p><img src="/2015/10/09/python-interative-mode-tab-completion/1.gif"><p>这样练习起来就方便很多了!</p>]]></content>
<summary type="html">
<p>本人使用的是mac os x 10.10.5版本,shell是zsh。</p>
<p>zsh的自定义配置在~/.oh-my-zsh/custom/my.zsh中。</p>
<p>首先在<code>~/.oh-my-zsh/custom/my.zsh</code>中配置如下:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> PYTHONSTARTUP=<span class="variable">$HOME</span>/.pythonrc.py</span><br></pre></td></tr></table></figure>
<p><em>Note:如果你的zsh没有自定义配置文件,你可以直接在<code>~/.zshrc</code>配置。</em></p>
</summary>
</entry>
<entry>
<title>git设置global ignore</title>
<link href="http://hushicai.github.io/2015/09/15/git-she-zhi-global-ignore.html"/>
<id>http://hushicai.github.io/2015/09/15/git-she-zhi-global-ignore.html</id>
<published>2015-09-15T09:28:26.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>在个人主目录下新建一个<code>~/.gitignore</code>文件,填上想全局忽略的文件:</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">cscope.files</span><br><span class="line">cscope.out</span><br></pre></td></tr></table></figure><p>然后在<code>~/.gitconfig</code>中配置一下就行了:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global core.excludesfile ~/.gitignore</span><br></pre></td></tr></table></figure><p>执行完以上命令后,在<code>~/.gitconfig</code>中会添加一个新项目:</p><figure class="highlight plain"><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">[core]</span><br><span class="line">excludesfile = /Users/hushicai/.gitignore</span><br></pre></td></tr></table></figure><p>搞定!</p>]]></content>
<summary type="html">
<p>在个人主目录下新建一个<code>~/.gitignore</code>文件,填上想全局忽略的文件:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="lin
</summary>
</entry>
<entry>
<title>删除git submodule</title>
<link href="http://hushicai.github.io/2015/05/28/delete-git-submodule.html"/>
<id>http://hushicai.github.io/2015/05/28/delete-git-submodule.html</id>
<published>2015-05-28T14:11:06.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>git添加submodule时,很酸爽,但是删除时,很蛋疼。</p><p>git貌似没有直接提供删除submodule的方法,如果要删除submodule,需要以下步骤:</p><ul><li>删除<code>.gitmodules</code>中对应的节点</li><li>添加<code>.gitmodules</code>到暂存区,<code>git add .gitmodules</code></li><li>删除<code>.git/config</code>中对应的节点</li><li>删除暂存区缓存,<code>git rm --cached path_to_submodule</code></li><li>删除<code>.git/modules/path_to_submodule</code>,<code>rm -rf .git/modules/path_to_submodule</code></li><li>删除工作区的submodule,<code>rm -rf path_to_submodule</code></li></ul><p>挺繁杂的……</p>]]></content>
<summary type="html">
<p>git添加submodule时,很酸爽,但是删除时,很蛋疼。</p>
<p>git貌似没有直接提供删除submodule的方法,如果要删除submodule,需要以下步骤:</p>
<ul>
<li>删除<code>.gitmodules</code>中对应的节点</li>
</summary>
</entry>
<entry>
<title>微信的一道前端面试题</title>
<link href="http://hushicai.github.io/2015/05/07/a-frontend-interview-question-of-weixin.html"/>
<id>http://hushicai.github.io/2015/05/07/a-frontend-interview-question-of-weixin.html</id>
<published>2015-05-07T15:03:28.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>今天听说了一道微信的前端面试题,内容大概如下:</p><blockquote><p>实现一个LazyMan,可以按照以下方式调用:<br>LazyMan(“Hank”)输出:<br>Hi! This is Hank!</p><p>LazyMan(“Hank”).sleep(10).eat(“dinner”)输出<br>Hi! This is Hank!<br>//等待10秒..<br>Wake up after 10<br>Eat dinner~</p><p>LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出<br>Hi This is Hank!<br>Eat dinner~<br>Eat supper~</p><p>LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出<br>//等待5秒<br>Wake up after 5<br>Hi This is Hank!<br>Eat supper</p><p>以此类推。</p></blockquote><p>这题目我觉得挺有意思的,晚上下班回来就折腾了一下。</p><a id="more"></a><p>一个简单的做法就是使用队列+next。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">LazyMan</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> queue = [];</span><br><span class="line"> <span class="keyword">var</span> task = {</span><br><span class="line"> wait: <span class="function"><span class="keyword">function</span> (<span class="params">second</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Wake up after '</span> + second);</span><br><span class="line"> next();</span><br><span class="line"> }, second * <span class="number">1000</span>);</span><br><span class="line"> };</span><br><span class="line"> },</span><br><span class="line"> eat: <span class="function"><span class="keyword">function</span> (<span class="params">part</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Eat '</span> + part + <span class="string">'~'</span>);</span><br><span class="line"> next();</span><br><span class="line"> };</span><br><span class="line"> },</span><br><span class="line"> hi: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Hi! This is '</span> + name + <span class="string">'!'</span>);</span><br><span class="line"> next();</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> queue.push(task.hi);</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">next</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> fn = queue.shift();</span><br><span class="line"> fn && fn();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// flush later</span></span><br><span class="line"> setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> next();</span><br><span class="line"> }, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> sleep: <span class="function"><span class="keyword">function</span> (<span class="params">second</span>) </span>{</span><br><span class="line"> queue.push(task.wait(second));</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> },</span><br><span class="line"> sleepFirst: <span class="function"><span class="keyword">function</span> (<span class="params">second</span>) </span>{</span><br><span class="line"> queue.unshift(task.wait(second));</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> },</span><br><span class="line"> eat: <span class="function"><span class="keyword">function</span> (<span class="params">part</span>) </span>{</span><br><span class="line"> queue.push(task.eat(part));</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">exports.LazyMan = LazyMan;</span><br></pre></td></tr></table></figure><p>测试:</p><figure class="highlight javascript"><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="keyword">var</span> LazyMan = <span class="built_in">require</span>(<span class="string">'./LazyMan'</span>);</span><br><span class="line">LazyMan(<span class="string">'Hank'</span>).sleepFirst(<span class="number">10</span>).eat(<span class="string">'breadfast'</span>).sleep(<span class="number">5</span>).eat(<span class="string">'lunch'</span>).sleep(<span class="number">10</span>).eat(<span class="string">'dinner'</span>);</span><br></pre></td></tr></table></figure><p>该问题也可以使用Promise来解决。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createWaitPromise</span>(<span class="params">second</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> resolve(<span class="string">'Wake up after '</span> + second);</span><br><span class="line"> }, second * <span class="number">1000</span>);</span><br><span class="line"> });</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">LazyMan</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> p = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve, reject</span>) </span>{</span><br><span class="line"> resolve(<span class="string">'Hi! This is '</span> + name + <span class="string">'!'</span>);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> sleep: <span class="function"><span class="keyword">function</span> (<span class="params">second</span>) </span>{</span><br><span class="line"> p = p.then(<span class="function"><span class="keyword">function</span> (<span class="params">msg</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(msg);</span><br><span class="line"> <span class="keyword">return</span> createWaitPromise(second);</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> },</span><br><span class="line"> sleepFirst: <span class="function"><span class="keyword">function</span> (<span class="params">second</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> op = p;</span><br><span class="line"> p = createWaitPromise(second).then(<span class="function"><span class="keyword">function</span> (<span class="params">msg</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(msg);</span><br><span class="line"> <span class="keyword">return</span> op;</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> },</span><br><span class="line"> eat: <span class="function"><span class="keyword">function</span> (<span class="params">part</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> pn = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span> (<span class="params">resolve</span>) </span>{</span><br><span class="line"> resolve(<span class="string">'Eat '</span> + part + <span class="string">'~'</span>);</span><br><span class="line"> });</span><br><span class="line"> p = p.then(<span class="function"><span class="keyword">function</span> (<span class="params">msg</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(msg);</span><br><span class="line"> <span class="keyword">return</span> pn;</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> },</span><br><span class="line"> print: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> p.then(<span class="function"><span class="keyword">function</span> (<span class="params">msg</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(msg);</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">exports.LazyMan = LazyMan;</span><br></pre></td></tr></table></figure><p>测试:</p><figure class="highlight javascript"><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="keyword">var</span> LazyMan = <span class="built_in">require</span>(<span class="string">'./LazyMan'</span>);</span><br><span class="line">LazyMan(<span class="string">'Hank'</span>).sleepFirst(<span class="number">5</span>).eat(<span class="string">'breadfast'</span>).sleep(<span class="number">5</span>).eat(<span class="string">'lunch'</span>).sleep(<span class="number">5</span>).eat(<span class="string">'dinner'</span>).print();</span><br></pre></td></tr></table></figure><p>print是用来取出最后一个promise的消息。</p><p>当然也可以用<a href="https://github.com/caolan/async" target="_blank" rel="noopener">async</a>来做。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createWaitFunc</span>(<span class="params">second</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params">callback</span>) </span>{</span><br><span class="line"> setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Wake up after '</span> + second);</span><br><span class="line"> callback(<span class="literal">null</span>);</span><br><span class="line"> }, second * <span class="number">1000</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">LazyMan</span>(<span class="params">name</span>) </span>{</span><br><span class="line"> <span class="comment">// var async = require('async');</span></span><br><span class="line"> <span class="keyword">var</span> chain = [];</span><br><span class="line"> chain.push(</span><br><span class="line"> <span class="function"><span class="keyword">function</span> (<span class="params">callback</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Hi! This is '</span> + name + <span class="string">'!'</span>);</span><br><span class="line"> callback(<span class="literal">null</span>);</span><br><span class="line"> }</span><br><span class="line"> );</span><br><span class="line"> setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> <span class="keyword">async</span> = <span class="built_in">require</span>(<span class="string">'async'</span>);</span><br><span class="line"> <span class="keyword">async</span>.series(chain);</span><br><span class="line"> }, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> sleep: <span class="function"><span class="keyword">function</span> (<span class="params">second</span>) </span>{</span><br><span class="line"> chain.push(</span><br><span class="line"> createWaitFunc(second)</span><br><span class="line"> );</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> },</span><br><span class="line"> sleepFirst: <span class="function"><span class="keyword">function</span> (<span class="params">second</span>) </span>{</span><br><span class="line"> chain.unshift(</span><br><span class="line"> createWaitFunc(second)</span><br><span class="line"> );</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> },</span><br><span class="line"> eat: <span class="function"><span class="keyword">function</span> (<span class="params">part</span>) </span>{</span><br><span class="line"> chain.push(</span><br><span class="line"> <span class="function"><span class="keyword">function</span> (<span class="params">callback</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Eat '</span> + part + <span class="string">'~'</span>);</span><br><span class="line"> callback(<span class="literal">null</span>);</span><br><span class="line"> }</span><br><span class="line"> );</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">exports.LazyMan = LazyMan;</span><br></pre></td></tr></table></figure><p>测试:</p><figure class="highlight javascript"><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="keyword">var</span> LazyMan = <span class="built_in">require</span>(<span class="string">'./LazyMan'</span>);</span><br><span class="line">LazyMan(<span class="string">'Hank'</span>).sleepFirst(<span class="number">5</span>).eat(<span class="string">'breadfast'</span>).sleep(<span class="number">5</span>).eat(<span class="string">'lunch'</span>).sleep(<span class="number">5</span>).eat(<span class="string">'dinner'</span>);</span><br></pre></td></tr></table></figure><p>以上测试都在nodejs环境跑,欢迎拍砖~!</p>]]></content>
<summary type="html">
<p>今天听说了一道微信的前端面试题,内容大概如下:</p>
<blockquote>
<p>实现一个LazyMan,可以按照以下方式调用:<br>LazyMan(“Hank”)输出:<br>Hi! This is Hank!</p>
<p>LazyMan(“Hank”).sleep(10).eat(“dinner”)输出<br>Hi! This is Hank!<br>//等待10秒..<br>Wake up after 10<br>Eat dinner~</p>
<p>LazyMan(“Hank”).eat(“dinner”).eat(“supper”)输出<br>Hi This is Hank!<br>Eat dinner~<br>Eat supper~</p>
<p>LazyMan(“Hank”).sleepFirst(5).eat(“supper”)输出<br>//等待5秒<br>Wake up after 5<br>Hi This is Hank!<br>Eat supper</p>
<p>以此类推。</p>
</blockquote>
<p>这题目我觉得挺有意思的,晚上下班回来就折腾了一下。</p>
</summary>
</entry>
<entry>
<title>【翻译】开发者工具时间轴:现在提供了全部的故事</title>
<link href="http://hushicai.github.io/2015/04/29/devtools-timeline-improvements.html"/>
<id>http://hushicai.github.io/2015/04/29/devtools-timeline-improvements.html</id>
<published>2015-04-29T02:23:09.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>原文地址:<a href="http://updates.html5rocks.com/2015/04/devtools-timeline-improvements" target="_blank" rel="noopener">http://updates.html5rocks.com/2015/04/devtools-timeline-improvements</a></p><p>开发者工具的<a href="https://developer.chrome.com/devtools/docs/timeline" target="_blank" rel="noopener">timeline panel</a>一直以来都是在性能优化路上最佳的第一站。 这个关于你的应用程序活动的集中化概览,可以帮助你分析花费在loading、scripting、rendering和repainting上的时间。 最近,我们升级了timeline面板,增加了更多的使用方法,以便你可以更加深入地了解你的应用程序性能。</p><p>我们添加了以下特性:</p><ul><li>集成<a href="#Integrated_JavaScript_Profiler">Javascript profiler</a>(包括了火焰图表)</li><li><a href="#Frame_Viewer">frame viewer</a>,帮助你查看组合图层。</li><li><a href="#Paint_Profiler">paint profiler</a>,入木三分地剖析了浏览器渲染活动。</li></ul><p>注意,使用本文中描述的<strong>Paint</strong>捕获选项会导致一些性能负担,所以只有你需要它们的时候,才去勾选它们。</p><a id="more"></a><h2 id="Integrated-JavaScript-Profiler"><a href="#Integrated-JavaScript-Profiler" class="headerlink" title="Integrated JavaScript Profiler"></a>Integrated JavaScript Profiler</h2><p>如果你曾经玩过<strong>Profiles</strong>面板,那么你应该很熟悉<a href="https://developer.chrome.com/devtools/docs/cpu-profiling" target="_blank" rel="noopener">Javascript CPU Profiler</a>。这个工具估量了执行时间都花费在你的Javascript函数哪些地方。通过火焰图表来查看Javascript profiles,你可以可视化你的Javascript随着时间推移的执行过程。</p><p>现在,你可以在<strong>Timeline</strong>面板上获得细粒度的Javascript执行故障。通过勾选<strong>JS Profiler</strong>捕获选项,你可以在时间轴上看到你的Javascript调用栈,同时还有一些其他浏览器事件。 添加这些特性到时间轴上,可以帮助你流程化你的调试工作。但是不仅如此,它还允许你查看上下文中的Javascript代码,并且还可以标识出影响页面加载时间和渲染的那部分代码。</p><p>除了该Javascript profiler,我们还集成了一个火焰图表到<strong>Timeline</strong>面板中。你现在可以通过两种方式查看你的应用程序活动,一种是经典的瀑布图,一种是一个火焰图表。 面板上的火焰图标<span class="article-inline-img"><img src="/2015/04/29/devtools-timeline-improvements/flame-icon.png"></span>允许你在这两种视图之间切换。</p><img src="/2015/04/29/devtools-timeline-improvements/javascript-profiler.png"><p class="article-center-p">在时间轴上,使用JS Profiler捕获选项和火焰图表视图来研究调用栈。</p><p>提示:可以使用按键<code>WASD</code>来缩放和平移火焰图表。<code>Shift + 拖动</code>可以画一个选择框。</p><h2 id="Frame-Viewer"><a href="#Frame-Viewer" class="headerlink" title="Frame Viewer"></a>Frame Viewer</h2><p><a href="http://www.html5rocks.com/en/tutorials/speed/layers/" target="_blank" rel="noopener">layer compositing</a>的艺术是浏览器不为人知的另一方面。当节俭并小心地使用时,图层可以帮助避免一些昂贵的重绘操作,并且产生巨大的性能收益。但是往往无法明显地预测浏览器将如何组合你的内容。 使用Timeline面板中新的<strong>Paint</strong>捕获选项,你可以显式地查看一个记录中每一帧的组合图层。</p><p>当你选择在<strong>Main Thread</strong>上方的某一个灰色的帧条时,它的图层面板提供了一个图层的可视化模型,这些图层组成了你的应用程序。</p><p>你可以缩放、旋转、拖动这些图层来查看它们的内容。光标移到一个图层上,会揭示出它在页面上的当前位置。右击一个图层可以让你跳到<strong>Elements</strong>面板中相应的节点上。这些功能向你展示了什么被提升为一个图层。如果你选择一个图层,你也可以在签名为<strong>Compositing Reasons</strong>的行中看到它为什么被提升了。</p><img src="/2015/04/29/devtools-timeline-improvements/compositing-reasons.png"><p class="article-center-p">从<a href="http://tympanus.net/Development/ScatteredPolaroidsGallery/" target="_blank" rel="noopener">Codrops’ Scattered Polaroids Gallery</a>里检查一个图层来揭晓浏览器组合图层的原因。</p><p><em>ps: 一个元素可以被提升到一个图层中,当它具备某些特性时,详见<a href="http://www.html5rocks.com/en/tutorials/speed/layers/" target="_blank" rel="noopener">compositing layers</a>。</em></p><h2 id="Paint-Profiler"><a href="#Paint-Profiler" class="headerlink" title="Paint Profiler"></a>Paint Profiler</h2><p>最后但并非不重要,我们已经添加了paint profiler来帮助你找出由于昂贵的绘制引发的卡顿。这个特性充实了时间轴,我们可以看到更多关于Chrome在绘制事件期间的工作信息。</p><p>对于初学者,现在可以更容易地辨别可见内容与绘制事件之间的对应关系。当你在时间轴上选择一个绿色的绘制事件(<strong>Main<br>Thread</strong>下方),<strong>Details</strong>面板将为你展示已经绘制的实际像素的预览。</p><img src="/2015/04/29/devtools-timeline-improvements/paint-capture.png"><p class="article-center-p">使用<strong>paiint</strong>捕获选项预览浏览器已经绘制的像素。</p><p>如果你真想深究,切换到<strong>Paint Profiler</strong>面板上。这个profiler为你展示了浏览器在选中的绘制事件中所执行的准确的绘制命令。 为了帮助你关联这些本地命令到你应用程序中的实际内容,你可以右击<strong>draw*</strong>调用并直接跳转到<strong>Elements</strong>面板上的对应的节点。</p><img src="/2015/04/29/devtools-timeline-improvements/draw-calls.png"><p>那个横跨在面板顶部上的小时间轴可以让你重播绘制进程,然后让你对哪些浏览器绘制操作是昂贵的有所了解。绘图操作是颜色编码的,如下:<span style="color: pink;">pink</span>(shapes)、<span style="color: blue;">blue</span>(bitmap)、<span style="color:green;">green</span>(text)、<span style="color:purple">purple</span>(misc.)。条形高表示调用过程,所以研究高的条形可以帮助你了解一个特定的绘制是怎么昂贵的。</p><h2 id="Profile-and-profit"><a href="#Profile-and-profit" class="headerlink" title="Profile and profit!"></a>Profile and profit!</h2><p>当涉及到性能优化时,浏览器的知识是难以置信地有用。管中窥豹,这些时间轴更新足以帮助阐明你的代码和Chrome渲染进程之间的关系。试试时间轴上的这些更新吧,然后看看Chrome DevTools能做些什么来增强你的解决卡顿问题的工作流程。</p><p><em>ps: 原文有几个视频,推荐大家去看看。</em></p>]]></content>
<summary type="html">
<p>原文地址:<a href="http://updates.html5rocks.com/2015/04/devtools-timeline-improvements" target="_blank" rel="noopener">http://updates.html5rocks.com/2015/04/devtools-timeline-improvements</a></p>
<p>开发者工具的<a href="https://developer.chrome.com/devtools/docs/timeline" target="_blank" rel="noopener">timeline panel</a>一直以来都是在性能优化路上最佳的第一站。 这个关于你的应用程序活动的集中化概览,可以帮助你分析花费在loading、scripting、rendering和repainting上的时间。 最近,我们升级了timeline面板,增加了更多的使用方法,以便你可以更加深入地了解你的应用程序性能。</p>
<p>我们添加了以下特性:</p>
<ul>
<li>集成<a href="#Integrated_JavaScript_Profiler">Javascript profiler</a>(包括了火焰图表)</li>
<li><a href="#Frame_Viewer">frame viewer</a>,帮助你查看组合图层。</li>
<li><a href="#Paint_Profiler">paint profiler</a>,入木三分地剖析了浏览器渲染活动。</li>
</ul>
<p>注意,使用本文中描述的<strong>Paint</strong>捕获选项会导致一些性能负担,所以只有你需要它们的时候,才去勾选它们。</p>
</summary>
<category term="翻译" scheme="http://hushicai.github.io/categories/%E7%BF%BB%E8%AF%91/"/>
</entry>
<entry>
<title>数组全排列</title>
<link href="http://hushicai.github.io/2015/04/28/fuck-array-permutation.html"/>
<id>http://hushicai.github.io/2015/04/28/fuck-array-permutation.html</id>
<published>2015-04-28T10:04:15.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>如何输出一个数组全部可能的排列组合?</p><p>比如<code>[1, 2]</code>,应该输出<code>[1, 2]</code>、<code>[2, 1]</code>。</p><p>再比如<code>[1, 2, 3]</code>,应该输出<code>[1, 2, 3]</code>、<code>[1, 3, 2]</code>、<code>[2, 1, 3]</code>、<code>[2, 3, 1]</code>、<code>[3, 1, 2]</code>、<code>[3, 2, 1]</code>。</p><p>观察以上数据,其实可以推断出,假设一组数<code>p = {r1, r2, r3, ..., rn}</code>,全排列表示为perm(p),数组中除rn之外的数据集合表示为pn = p - {rn}。</p><p>那么perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), …, rnperm(pn)。</p><p>数据全部可能的排列组合就是r1perm(p1),r2perm(p2),….,rnperm(pn)的集合。</p><a id="more"></a><p>算法:</p><figure class="highlight plain"><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">// 对从k到m的子数组进行排列</span><br><span class="line">perm(arr, k, m):</span><br><span class="line"> if k > m</span><br><span class="line"> // 递归结束,输出一个排列</span><br><span class="line"> console.log(arr);</span><br><span class="line"> else</span><br><span class="line"> for i from k to m</span><br><span class="line"> // 以arr[k]为开头的排列</span><br><span class="line"> // 先将i处的数交换到k处</span><br><span class="line"> // 那么剩下的数就为arr - {arr[k]}</span><br><span class="line"> swap(arr, k, i)</span><br><span class="line"> // 排列的问题就转换成arr[k]perm(arr, k + 1, m)</span><br><span class="line"> perm(arr, k + 1, m)</span><br><span class="line"> // 将原来的开头的数交换回去</span><br><span class="line"> // 继续以数组下一项为开头的排列</span><br><span class="line"> swap(arr, k, i)</span><br></pre></td></tr></table></figure><p>js实现如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">define(</span><br><span class="line"> <span class="function"><span class="keyword">function</span> (<span class="params">require</span>) </span>{</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">swap</span>(<span class="params">arr, i, j</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> temp = arr[i];</span><br><span class="line"> arr[i] = arr[j];</span><br><span class="line"> arr[j] = temp;</span><br><span class="line"> <span class="keyword">return</span> arr;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">perm</span>(<span class="params">arr, start, end, result</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (start > end) {</span><br><span class="line"> result.push(arr.slice(<span class="number">0</span>));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = start; i <= end; i++) {</span><br><span class="line"> swap(arr, start, i);</span><br><span class="line"> perm(arr, start + <span class="number">1</span>, end, result);</span><br><span class="line"> swap(arr, start, i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params">arr</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> result = [];</span><br><span class="line"> perm(arr, <span class="number">0</span>, arr.length - <span class="number">1</span>, result);</span><br><span class="line"> <span class="keyword">return</span> result;</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>使用方式:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">require</span>([<span class="string">'module-id'</span>], <span class="function"><span class="keyword">function</span> (<span class="params">perm</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> result = perm([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="built_in">JSON</span>.stringify(result));</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>输出<code>[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,2,1],[3,1,2]</code>。</p>]]></content>
<summary type="html">
<p>如何输出一个数组全部可能的排列组合?</p>
<p>比如<code>[1, 2]</code>,应该输出<code>[1, 2]</code>、<code>[2, 1]</code>。</p>
<p>再比如<code>[1, 2, 3]</code>,应该输出<code>[1, 2, 3]</code>、<code>[1, 3, 2]</code>、<code>[2, 1, 3]</code>、<code>[2, 3, 1]</code>、<code>[3, 1, 2]</code>、<code>[3, 2, 1]</code>。</p>
<p>观察以上数据,其实可以推断出,假设一组数<code>p = {r1, r2, r3, ..., rn}</code>,全排列表示为perm(p),数组中除rn之外的数据集合表示为pn = p - {rn}。</p>
<p>那么perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), …, rnperm(pn)。</p>
<p>数据全部可能的排列组合就是r1perm(p1),r2perm(p2),….,rnperm(pn)的集合。</p>
</summary>
</entry>
<entry>
<title>vim simple cursor moving</title>
<link href="http://hushicai.github.io/2015/04/27/vim-simple-cursor-moving.html"/>
<id>http://hushicai.github.io/2015/04/27/vim-simple-cursor-moving.html</id>
<published>2015-04-27T02:51:03.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>在vim normal模式下,你仅需几个按键,就可以健步如飞。</p><ul><li>到文件的开始处?</li></ul><p><code>gg</code></p><ul><li>到文件的结尾处?</li></ul><p><code>G</code></p><ul><li>到第n行?</li></ul><p><code>nG</code>或者<code>ngg</code>,其中n替换为行,比如第100行,<code>100G</code>或者<code>100gg</code></p><ul><li>当前行第一个非空白字符?</li></ul><p><code>^</code></p><ul><li>移到行首?</li></ul><p><code>0</code>,数字零。</p><ul><li>移到行尾?</li></ul><p><code>$</code></p><ul><li>下一行第一个非空字符?</li></ul><p><code><CR></code>,即回车键</p><ul><li>上一行第一个非空字符?</li></ul><p><code>-</code>,中横线。</p><ul><li>向前移到一个单词的结尾处?</li></ul><p><code>e</code></p><a id="more"></a><ul><li>向前移到一个单词的开始处?</li></ul><p><code>w</code></p><ul><li>向后移到一个单词的开始处?</li></ul><p><code>b</code></p><ul><li>移到屏幕顶端?</li></ul><p><code>H</code></p><ul><li>移到屏幕中间?</li></ul><p><code>M</code></p><ul><li>移到屏幕底端?</li></ul><p><code>L</code></p><ul><li>向前翻一页?</li></ul><p><code><C-F></code></p><ul><li>向后翻一页?</li></ul><p><code><C-B></code></p><ul><li>跳到相应项?</li></ul><p><code>%</code>,比如<text>,假设光标在字符<上,按下<code>%</code>,就会跳到字符<code>></code>上。</p><p>以上是一些基本的移动方式,当然还有更高级的,比如</p><ul><li>text-objects</li><li>mark</li></ul><p>这里就不展开了,有兴趣的可以自行<code>:help text-objects</code>、<code>:help mark</code>。</p>]]></content>
<summary type="html">
<p>在vim normal模式下,你仅需几个按键,就可以健步如飞。</p>
<ul>
<li>到文件的开始处?</li>
</ul>
<p><code>gg</code></p>
<ul>
<li>到文件的结尾处?</li>
</ul>
<p><code>G</code></p>
<ul>
<li>到第n行?</li>
</ul>
<p><code>nG</code>或者<code>ngg</code>,其中n替换为行,比如第100行,<code>100G</code>或者<code>100gg</code></p>
<ul>
<li>当前行第一个非空白字符?</li>
</ul>
<p><code>^</code></p>
<ul>
<li>移到行首?</li>
</ul>
<p><code>0</code>,数字零。</p>
<ul>
<li>移到行尾?</li>
</ul>
<p><code>$</code></p>
<ul>
<li>下一行第一个非空字符?</li>
</ul>
<p><code>&lt;CR&gt;</code>,即回车键</p>
<ul>
<li>上一行第一个非空字符?</li>
</ul>
<p><code>-</code>,中横线。</p>
<ul>
<li>向前移到一个单词的结尾处?</li>
</ul>
<p><code>e</code></p>
</summary>
<category term="vim" scheme="http://hushicai.github.io/categories/vim/"/>
<category term="vim" scheme="http://hushicai.github.io/tags/vim/"/>
<category term="cursor" scheme="http://hushicai.github.io/tags/cursor/"/>
<category term="moving" scheme="http://hushicai.github.io/tags/moving/"/>
</entry>
<entry>
<title>my vim completion setting</title>
<link href="http://hushicai.github.io/2015/04/24/my-vim-completion-setting.html"/>
<id>http://hushicai.github.io/2015/04/24/my-vim-completion-setting.html</id>
<published>2015-04-23T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>本人从事web前端开发,一直用vim作为开发工具。</p><p>最近一直在折腾completion这事,先后尝试了<code>youcompleteme</code>、<code>neocomplete</code>等工具,甚至直接使用vim内置的<code>ins-completion</code>,不过都不尽人意。</p><p>一顿折腾之后,总算弄了一套自己用着还算顺手的配置。</p><p>我期望completion可以干以下这些事</p><ul><li>标识符补全</li><li>智能补全(omni completion)</li><li>路径补全</li><li>snippets</li></ul><p>这些补全其实<code>ins-completion</code>已经可以搞定了,但是比较费劲,<code><c-x><c-o></code>、<code><c-x><c-f></code>…好多按键…</p><p>所以有了<code>youcompleteme</code>、<code>neocomplete</code>等工具。</p><p>试用了一番,<code>neocomplete</code>比较卡,放弃了,最后选择了<code>youcompleteme</code>。</p><h2 id="youcompleteme"><a href="#youcompleteme" class="headerlink" title="youcompleteme"></a>youcompleteme</h2><p>基本配置如下:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_min_num_of_chars_for_completion</span> = <span class="number">3</span> </span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_autoclose_preview_window_after_completion</span>=<span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_complete_in_comments</span> = <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_key_list_select_completion</span> = [<span class="string">'<tab>'</span>, <span class="string">'<c-n>'</span>, <span class="string">'<Down>'</span>]</span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_key_list_previous_completion</span> = [<span class="string">'<c-p>'</span>, <span class="string">'<Up>'</span>]</span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_confirm_extra_conf</span> = <span class="number">0</span></span><br></pre></td></tr></table></figure><a id="more"></a><p>标识符补全:</p><img src="/2015/04/24/my-vim-completion-setting/1.png"><p>ycm提供了一个<code>identifier-basedcompleter</code>,它会收集所有当前文件或者访问过的文件中的identifiers,当你输入时,ycm会查找它们,并提供completion。</p><p>路径补全:</p><img src="/2015/04/24/my-vim-completion-setting/2.png"><p>ycm提供了一个<code>filepath completer</code>来补全路径。</p><p>智能补全:</p><img src="/2015/04/24/my-vim-completion-setting/3.png"><p>ycm会为c-family语言、python等提供内置的completer,但对于javascript、php等语言,则使用vim的omnicompletion系统。</p><p>如上图所示,ycm能够正常的提供completion,不过,它只会在点号(.)之后才能开启补全,也就是说它不会补全全局预定义的变量/函数。</p><p>可能有人会问:第一张图中不是已经补全了吗?</p><p>没错,是补全了,但那不是<code>omni completion</code>提供的,而是ycm的identifier completer提供的,对于在buffer中已经出现的标识符,ycm会把它们当作候选项。</p><p>看一下这种情况:</p><img src="/2015/04/24/my-vim-completion-setting/4.png"><p><code>document</code>是dom提供给javascript的全局变量,但是这里没补全,显然ycm此时并没有启动omni completion。如果你用<code><c-x><c-o></code>手动触发omni completion,则可以得到补全。</p><img src="/2015/04/24/my-vim-completion-setting/5.png"><p>查了一下ycm的文档,发现有一个选项可以来控制是否触发omni completion:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_semantic_triggers</span> = {<span class="string">'javascript'</span>: [<span class="string">'.'</span>]}</span><br></pre></td></tr></table></figure><p>但是设置之后不管用,ycm其实已经移除了这个配置,但是文档没更新,太坑了!!!</p><p>为了能更快捷地触发全局变量的智能补全,我定义了两个快捷键:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span>! <span class="title">MyTabFunction</span> <span class="params">()</span></span></span><br><span class="line"> <span class="keyword">let</span> <span class="built_in">line</span> = <span class="built_in">getline</span>(<span class="string">'.'</span>)</span><br><span class="line"> <span class="keyword">let</span> substr = <span class="built_in">strpart</span>(<span class="built_in">line</span>, -<span class="number">1</span>, <span class="keyword">col</span>(<span class="string">'.'</span>)+<span class="number">1</span>)</span><br><span class="line"> <span class="keyword">let</span> substr = <span class="built_in">matchstr</span>(substr, <span class="string">"[^ \t]*$"</span>)</span><br><span class="line"> <span class="keyword">if</span> <span class="built_in">strlen</span>(substr) == <span class="number">0</span></span><br><span class="line"> <span class="keyword">return</span> <span class="string">"\<tab>"</span></span><br><span class="line"> <span class="keyword">endif</span></span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">pumvisible</span>() ? <span class="string">"\<c-n>"</span> : <span class="string">"\<c-x>\<c-o>"</span></span><br><span class="line"><span class="keyword">endfunction</span></span><br><span class="line"><span class="keyword">inoremap</span> <span class="symbol"><tab></span> <span class="symbol"><c-r></span>=MyTabFunction()<span class="symbol"><cr></span></span><br><span class="line"><span class="keyword">inoremap</span> <span class="symbol"><c-o></span> <span class="symbol"><c-x></span><span class="symbol"><c-o></span></span><br></pre></td></tr></table></figure><p>为啥要定义两个?主要是为了处理以下两种情况:</p><ol><li>没有候选项(completion-menu不显示)</li><li>有候选项,但不是智能补全的候选项,即completion-menu上的候选项是来自其他completer的,比如identifier、snippets</li></ol><p>第一种情况,可以直接使用<code><tab></code>来触发智能补全并选择候选项,但是第二种情况下,候选项不是我们想要的智能补全选项,我们需要重新触发智能补全,而此时<code><tab></code>是充当选择候选项的功能,并不适用,所以就再定义一个<code><c-o></code>快捷键(当然你也可以直接用<code><c-x><c-o></code>)。</p><p>ok, 现在我们只需要用<code><tab></code>或者<code><c-o></code>就可以强制触发智能补全了。</p><h2 id="ultisnips"><a href="#ultisnips" class="headerlink" title="ultisnips"></a>ultisnips</h2><p><code>ultisnips</code>可以很好地配合ycm,提供snippets补全。</p><p>安装了<code>ultisnips</code>之后,ycm有个配置<code>g:ycm_use_ultisnips_completer</code>可以来控制是否接收<code>ultisnips</code>的补全,默认为1。</p><img src="/2015/04/24/my-vim-completion-setting/6.png"><p>到目前为止,completion看起来好像已经很友好了。</p><p>其实不然,有些全局预定义函数/变量没有补全,比如<code>setTimeout</code>、<code>setInterval</code>等:</p><img src="/2015/04/24/my-vim-completion-setting/7.png"><p>一些html5提供的新方法也没有得到补全。</p><p>这个时候,我们可以定义<code>dictionary</code>来补全:</p><figure class="highlight vim"><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="keyword">set</span> <span class="built_in">complete</span>+=<span class="keyword">k</span></span><br><span class="line"><span class="keyword">set</span> dictionary+=~/data/github/dotfiles/<span class="keyword">vim</span>/dictionary/javascript.dict</span><br></pre></td></tr></table></figure><p>设置完<code>dictionary</code>之后,用<code><c-x><c-k></code>就可以得到补全。</p><p>不过,很遗憾,ycm并不会把dictionary加到候选项中。</p><h2 id="tern"><a href="#tern" class="headerlink" title="tern"></a>tern</h2><p>javascript作为一门动态类型语言,其本身的工程化能力差,omni<br>completion能提供的补全功能有限,比如无法补全类成员、其他文件的函数定义等。</p><p>tern应运而生,它是一个javascript代码分析引擎,和一个代码编辑器插件一起使用,可以增强该编辑器对智能化javascript编程的支持,提供了以下特性:</p><ul><li>变量和属性自动补全</li><li>函数参数提示</li><li>查询一个表达式的类型</li><li>查找某些函数/变量的定义</li><li>自动化反射</li></ul><p>tern有一个<code>tern_for_vim</code>插件,用来增强vim对智能化javascript编程的支持。</p><p>安装<code>tern_for_vim</code>之后,配置:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="variable">g:tern_show_signature_in_pum</span> = <span class="number">1</span></span><br></pre></td></tr></table></figure><p><em>ps: 具体怎么安装详见<a href="http://ternjs.net/doc/manual.html" target="_blank" rel="noopener">tern doc</a>。</em></p><p>再配置以下<code>.tern-project</code>:</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> <span class="attr">"libs"</span>: [</span><br><span class="line"> <span class="string">"browser"</span>,</span><br><span class="line"> <span class="string">"jquery"</span>,</span><br><span class="line"> <span class="string">"ecma5"</span></span><br><span class="line"> ],</span><br><span class="line"> <span class="attr">"plugins"</span>: {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>completion现在变成这样:</p><img src="/2015/04/24/my-vim-completion-setting/8.png"><p>还可以补全jquery:</p><img src="/2015/04/24/my-vim-completion-setting/9.png"><p>有了tern,我们现在也可以补全setInterval/setTimeout等全局函数了:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">set[tab]</span><br></pre></td></tr></table></figure><p>效果如下:</p><img src="/2015/04/24/my-vim-completion-setting/10.png"><p>很高大上,有木有。</p><p>有了tern,敲javascript代码,腰不酸了,腿不疼了,实乃居家码字之首选!</p>]]></content>
<summary type="html">
<p>本人从事web前端开发,一直用vim作为开发工具。</p>
<p>最近一直在折腾completion这事,先后尝试了<code>youcompleteme</code>、<code>neocomplete</code>等工具,甚至直接使用vim内置的<code>ins-completion</code>,不过都不尽人意。</p>
<p>一顿折腾之后,总算弄了一套自己用着还算顺手的配置。</p>
<p>我期望completion可以干以下这些事</p>
<ul>
<li>标识符补全</li>
<li>智能补全(omni completion)</li>
<li>路径补全</li>
<li>snippets</li>
</ul>
<p>这些补全其实<code>ins-completion</code>已经可以搞定了,但是比较费劲,<code>&lt;c-x&gt;&lt;c-o&gt;</code>、<code>&lt;c-x&gt;&lt;c-f&gt;</code>…好多按键…</p>
<p>所以有了<code>youcompleteme</code>、<code>neocomplete</code>等工具。</p>
<p>试用了一番,<code>neocomplete</code>比较卡,放弃了,最后选择了<code>youcompleteme</code>。</p>
<h2 id="youcompleteme"><a href="#youcompleteme" class="headerlink" title="youcompleteme"></a>youcompleteme</h2><p>基本配置如下:</p>
<figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_min_num_of_chars_for_completion</span> = <span class="number">3</span> </span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_autoclose_preview_window_after_completion</span>=<span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_complete_in_comments</span> = <span class="number">1</span></span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_key_list_select_completion</span> = [<span class="string">'&lt;tab&gt;'</span>, <span class="string">'&lt;c-n&gt;'</span>, <span class="string">'&lt;Down&gt;'</span>]</span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_key_list_previous_completion</span> = [<span class="string">'&lt;c-p&gt;'</span>, <span class="string">'&lt;Up&gt;'</span>]</span><br><span class="line"><span class="keyword">let</span> <span class="variable">g:ycm_confirm_extra_conf</span> = <span class="number">0</span></span><br></pre></td></tr></table></figure>
</summary>
<category term="vim" scheme="http://hushicai.github.io/categories/vim/"/>
<category term="vim" scheme="http://hushicai.github.io/tags/vim/"/>
<category term="completion" scheme="http://hushicai.github.io/tags/completion/"/>
<category term="youcompleteme" scheme="http://hushicai.github.io/tags/youcompleteme/"/>
<category term="supertab" scheme="http://hushicai.github.io/tags/supertab/"/>
<category term="ultisnips" scheme="http://hushicai.github.io/tags/ultisnips/"/>
<category term="tern" scheme="http://hushicai.github.io/tags/tern/"/>
</entry>
<entry>
<title>服务器推技术之EventSource</title>
<link href="http://hushicai.github.io/2014/12/02/fu-wu-qi-tui-ji-shu-zhi-eventsource.html"/>
<id>http://hushicai.github.io/2014/12/02/fu-wu-qi-tui-ji-shu-zhi-eventsource.html</id>
<published>2014-12-01T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>最近在看服务器推技术时,发现了一项新的技术:<strong>EventSource</strong>。</p><p>w3c上有个草案描述了它:<a href="http://dev.w3.org/html5/eventsource/" target="_blank" rel="noopener">Server-Send Events</a>。</p><p>回想一下我们之前用到的服务器推技术:</p><ul><li><code>polling</code>:客户端不断轮询。</li><li><code>long polling</code>:服务端在数据未就绪时,挂起请求。</li></ul><p>这两种技术都存在一定的局限,我们需要服务器主动推送数据。</p><p>于是有了<code>WebSocket</code>,但它是双向的(服务端<——>客户端)。</p><p>有的时候,我们并不需要从客户端发送消息,我们只需要从服务端推送消息,<code>EventSource</code>应运而生。</p><p><code>EventSource</code>是单向的(服务端——>客户端),它直接使用http协议来传输数据(与<code>WebSocket</code>不同,<code>EventSource</code>不需要专门的协议)。</p><a id="more"></a><p>客户端, client.html:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (<span class="built_in">window</span>.EventSource) {</span><br><span class="line"> <span class="keyword">var</span> source = <span class="keyword">new</span> EventSource(<span class="string">'/stream'</span>);</span><br><span class="line"></span><br><span class="line"> source.addEventListener(<span class="string">'message'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(e.data);</span><br><span class="line"> }, <span class="literal">false</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>服务端, server.js:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">'http'</span>);</span><br><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"></span><br><span class="line">http.createServer(<span class="function"><span class="keyword">function</span>(<span class="params">req, res</span>) </span>{</span><br><span class="line"> <span class="keyword">if</span> (req.headers.accept && req.headers.accept == <span class="string">'text/event-stream'</span>) {</span><br><span class="line"> <span class="keyword">if</span> (req.url == <span class="string">'/stream'</span>) {</span><br><span class="line"> sendSSE(req, res);</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> res.writeHead(<span class="number">404</span>);</span><br><span class="line"> res.end();</span><br><span class="line"> }</span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> res.writeHead(<span class="number">200</span>, {<span class="string">'Content-Type'</span>: <span class="string">'text/html'</span>});</span><br><span class="line"> res.write(fs.readFileSync(__dirname + <span class="string">'/client.html'</span>));</span><br><span class="line"> res.end();</span><br><span class="line"> }</span><br><span class="line">}).listen(<span class="number">8000</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sendSSE</span>(<span class="params">req, res</span>) </span>{</span><br><span class="line"> res.writeHead(<span class="number">200</span>, {</span><br><span class="line"> <span class="string">'Content-Type'</span>: <span class="string">'text/event-stream'</span>,</span><br><span class="line"> <span class="string">'Cache-Control'</span>: <span class="string">'no-cache'</span>,</span><br><span class="line"> <span class="string">'Connection'</span>: <span class="string">'keep-alive'</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">var</span> id = (<span class="keyword">new</span> <span class="built_in">Date</span>()).toLocaleTimeString();</span><br><span class="line"></span><br><span class="line"> setInterval(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> constructSSE(res, id, (<span class="keyword">new</span> <span class="built_in">Date</span>()).toLocaleTimeString());</span><br><span class="line"> }, <span class="number">5000</span>);</span><br><span class="line"></span><br><span class="line"> constructSSE(res, id, (<span class="keyword">new</span> <span class="built_in">Date</span>()).toLocaleTimeString());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">constructSSE</span>(<span class="params">res, id, data</span>) </span>{</span><br><span class="line"> res.write(<span class="string">'id: '</span> + id + <span class="string">'\n'</span>);</span><br><span class="line"> res.write(<span class="string">"data: "</span> + data + <span class="string">'\n\n'</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>EventSource</code>的<code>content-type</code>是<code>text/event-stream</code>,数据传输格式:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">data: xxxxxxx\n\n</span><br></pre></td></tr></table></figure><p>多行的数据:</p><figure class="highlight plain"><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">data: xxxxxxxx\n</span><br><span class="line">data: xxxxxxxx\n\n</span><br></pre></td></tr></table></figure><p>最后一行使用两个<code>\n</code>。</p><p>我们可以使用<code>EventSource</code>传输json格式数据:</p><figure class="highlight plain"><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">data: {\n</span><br><span class="line">data: "name": "hushicai"\n</span><br><span class="line">data: }\n\n</span><br></pre></td></tr></table></figure><p>客户端接收到数据后,可以调用<code>JSON.parse</code>解析出json数据。</p><h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><ul><li><a href="http://www.html5rocks.com/en/tutorials/eventsource/basics/" target="_blank" rel="noopener">http://www.html5rocks.com/en/tutorials/eventsource/basics/</a></li></ul>]]></content>
<summary type="html">
<p>最近在看服务器推技术时,发现了一项新的技术:<strong>EventSource</strong>。</p>
<p>w3c上有个草案描述了它:<a href="http://dev.w3.org/html5/eventsource/" target="_blank" rel="noopener">Server-Send Events</a>。</p>
<p>回想一下我们之前用到的服务器推技术:</p>
<ul>
<li><code>polling</code>:客户端不断轮询。</li>
<li><code>long polling</code>:服务端在数据未就绪时,挂起请求。</li>
</ul>
<p>这两种技术都存在一定的局限,我们需要服务器主动推送数据。</p>
<p>于是有了<code>WebSocket</code>,但它是双向的(服务端&lt;——&gt;客户端)。</p>
<p>有的时候,我们并不需要从客户端发送消息,我们只需要从服务端推送消息,<code>EventSource</code>应运而生。</p>
<p><code>EventSource</code>是单向的(服务端——&gt;客户端),它直接使用http协议来传输数据(与<code>WebSocket</code>不同,<code>EventSource</code>不需要专门的协议)。</p>
</summary>
<category term="服务器推" scheme="http://hushicai.github.io/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%8E%A8/"/>
<category term="polling" scheme="http://hushicai.github.io/tags/polling/"/>
<category term="long polling" scheme="http://hushicai.github.io/tags/long-polling/"/>
<category term="WebSocket" scheme="http://hushicai.github.io/tags/WebSocket/"/>
<category term="EventSource" scheme="http://hushicai.github.io/tags/EventSource/"/>
</entry>
<entry>
<title>将NodeList转成Array</title>
<link href="http://hushicai.github.io/2014/12/01/jiang-nodelist-zhuan-cheng-array.html"/>
<id>http://hushicai.github.io/2014/12/01/jiang-nodelist-zhuan-cheng-array.html</id>
<published>2014-11-30T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p><code>NodeList</code>是一个Dom概念,其定义如下:</p><pre><code>interface NodeList { Node item(in unsigned long index); readonly attribute unsigned long length;};</code></pre><p>它有一个方法和一个属性,可以通过<code>item</code>方法来获得指定的元素:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nodeList.item(<span class="number">1</span>);</span><br></pre></td></tr></table></figure><p>也可以像数组一样,用下标来访问:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nodeList[<span class="number">1</span>];</span><br></pre></td></tr></table></figure><p>但它不是数组,其原型链如下:</p><pre><code>myNodeList ——> NodeList.prototype ——> Object.prototype ——> null</code></pre><p>而数组的原型链则为:</p><pre><code>myArray ——> Array.prototype ——> Object.prototype ——> null</code></pre><p><code>NodeList</code>没有数组的那些方法,对它进行遍历不是很方便,我们得先把它转成数组。</p><p>借助<code>call</code>以及<code>Array.prototype.slice</code>可以做到:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> myArray = <span class="built_in">Array</span>.prototype.slice.call(myNodeList);</span><br></pre></td></tr></table></figure><p><code>call</code>是把<code>Array.prototype</code>中的<code>this</code>指向myNodeList,<code>slice</code>方法要求this所指的对象有一个length参数,而刚好<code>NodeList</code>就有。</p><p><code>Array.prototype.slice</code>具体如何工作的,参见<a href="http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.10" target="_blank" rel="noopener">ecma</a>。</p>]]></content>
<summary type="html">
<p><code>NodeList</code>是一个Dom概念,其定义如下:</p>
<pre><code>interface NodeList {
Node item(in unsigned long index);
readonl
</summary>
<category term="NodeList" scheme="http://hushicai.github.io/tags/NodeList/"/>
<category term="Array" scheme="http://hushicai.github.io/tags/Array/"/>
<category term="slice" scheme="http://hushicai.github.io/tags/slice/"/>
</entry>
<entry>
<title>nerdcommenter注释符后添加空格</title>
<link href="http://hushicai.github.io/2014/08/20/nerdcommenter-zhu-shi-fu-hou-tian-jia-kong-ge.html"/>
<id>http://hushicai.github.io/2014/08/20/nerdcommenter-zhu-shi-fu-hou-tian-jia-kong-ge.html</id>
<published>2014-08-19T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>在vim中使用nerdcommenter注释时,我们一般用<code><leader>c<space></code>来自动添加或者去掉注释。</p><p>假设代码如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> name = <span class="string">"hushicai"</span>;</span><br></pre></td></tr></table></figure><p>将鼠标移到该行代码上,用<code><leader>c<space></code>进行注释,注释后应该是这样的:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//var name = "hushicai";</span></span><br></pre></td></tr></table></figure><p>然而,这可能会不符合某些团队的代码规范,比如我们团队,进行jshint之后,会提示这样的warning:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">edp WARN → line 1, col 0: Missing space after line comment</span><br></pre></td></tr></table></figure><p>意思就是要在单行注释的注释分隔符后面加个空格:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// var name = "hushicai";</span></span><br></pre></td></tr></table></figure><p>好吧,既然是规范,那我就不得不遵守了。</p><p>看了一眼nerdcommenter的文档,发现有这么一个配置可以解决问题:</p><figure class="highlight vim"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> NERDSpaceDelims=<span class="number">1</span></span><br></pre></td></tr></table></figure><p>ok,现在我们再使用<code><leader>c<space></code>进行自动注释,就可以按照规范在注释符后加一个空格了。</p>]]></content>
<summary type="html">
<p>在vim中使用nerdcommenter注释时,我们一般用<code>&lt;leader&gt;c&lt;space&gt;</code>来自动添加或者去掉注释。</p>
<p>假设代码如下:</p>
<figure class="highlight javascript
</summary>
<category term="nerdcommenter" scheme="http://hushicai.github.io/tags/nerdcommenter/"/>
<category term="space" scheme="http://hushicai.github.io/tags/space/"/>
<category term="空格" scheme="http://hushicai.github.io/tags/%E7%A9%BA%E6%A0%BC/"/>
</entry>
<entry>
<title>ios fixed定位问题</title>
<link href="http://hushicai.github.io/2014/08/19/ios-fixed-ding-wei-wen-ti.html"/>
<id>http://hushicai.github.io/2014/08/19/ios-fixed-ding-wei-wen-ti.html</id>
<published>2014-08-18T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>在ios5之前,我们如果要实现fixed导航条,我们得依赖iscroll来支持。</p><p>不过从ios5.1以来,fixed定位就已经支持了,但很遗憾,ios现在对它还只是半支持。</p><p>在大部分情况下,fixed表现得没有什么问题。</p><img src="/2014/08/19/ios-fixed-ding-wei-wen-ti/1.png"><p>但是在某些情况下,会出现一些比较奇葩的问题,比如fixed元素中存在输入框子元素,这个时候就会跪了。</p><a id="more"></a><p>可以看到,fixed定位的元素跑到中间去了,这种问题一般出现在页面有scrollTop并且输入框获得了焦点的情况下!</p><p><em>Note: 应该是由软键盘引起的问题。</em></p><p>怎么解决这种问题呢?我目前知道的主要有三种办法,假设HTML代码结构为:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE html></span></span><br><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>fixed<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"> header {</span></span><br><span class="line"><span class="undefined"> position: fixed;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> </span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">header</span>></span><span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"search"</span> <span class="attr">placeholder</span>=<span class="string">"请输入搜索词"</span> /></span><span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"container"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><h2 id="方法一"><a href="#方法一" class="headerlink" title="方法一"></a>方法一</h2><p>在输入框获得焦点时,将fixed改成absolute,并将top值设置为页面此时的scrollTop,然后在输入框失去焦点时,改回fixed。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onFocus</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.main.style.position = <span class="string">'absolute'</span>;</span><br><span class="line"> <span class="keyword">this</span>.main.style.top = <span class="built_in">document</span>.body.scrollTop + <span class="string">'px'</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onBlur</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.main.style.position = <span class="string">'fixed'</span>;</span><br><span class="line"> <span class="keyword">this</span>.main.style.top = <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>此外我们还得做一些额外的处理,比如禁止页面滚动,为啥要禁止滚动?</p><p>因为软键盘弹起的时候,用户还是可以滚动页面的,一旦用户往下滚动了页面,header也随着往下滚动了(因为此时它是absolute的)。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onTouchMove</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> e.preventDefault();</span><br><span class="line"> e.stopPropagation();</span><br><span class="line">};</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onFocus</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.main.style.position = <span class="string">'absolute'</span>;</span><br><span class="line"> <span class="keyword">this</span>.main.style.top = <span class="built_in">document</span>.body.scrollTop + <span class="string">'px'</span>;</span><br><span class="line"> <span class="built_in">document</span>.body.addEventListener(<span class="string">'touchmove'</span>, onTouchMove, <span class="literal">false</span>);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onBlur</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.main.style.position = <span class="string">'fixed'</span>;</span><br><span class="line"> <span class="keyword">this</span>.main.style.top = <span class="number">0</span>;</span><br><span class="line"> <span class="built_in">document</span>.body.removeEventListener(<span class="string">'touchmove'</span>, onTouchMove);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这种方法基本能解决大部分需求,但是在输入框有搜索提示的时候也会挂,因为我们禁止了滚动,而搜索提示通常应该要能往下滚动。</p><h2 id="方法二"><a href="#方法二" class="headerlink" title="方法二"></a>方法二</h2><p>在输入框的<code>touchstart</code>事件发生时,将fixed元素改成static,然后再将焦点focus到输入框中,然后输入框blur时,再将其设置成fixed:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">input.addEventListener(<span class="string">'touchstart'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> main.style.position = <span class="string">'static'</span>;</span><br><span class="line"> input.focus();</span><br><span class="line"> e.preventDefault();</span><br><span class="line">}, <span class="literal">false</span>);</span><br><span class="line">input.addEventListener(<span class="string">'blur'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> main.style.position = <span class="string">'fixed'</span>;</span><br><span class="line">}, <span class="literal">false</span>);</span><br></pre></td></tr></table></figure><p>这种方案的原理就是先将fixed元素改成static,这样该元素就会回到页面顶部(正常流),<br>然后调用输入框的focus方法,将焦点移到输入框中,此时页面视角也会跳到顶部。</p><p><em>Note: 优酷无线首页现在就是这么做的。</em></p><h2 id="方法三"><a href="#方法三" class="headerlink" title="方法三"></a>方法三</h2><p>这种方案是将header和container都设置成absolute,然后只滚动container。</p><p>这种的方法主要依赖ios5.1以后提供的<code>-webkit-overflow-scrolling</code>css属性。</p><p>HTML代码结构:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE html></span></span><br><span class="line"><span class="tag"><<span class="name">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span> /></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>fixed<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">style</span>></span><span class="undefined"></span></span><br><span class="line"><span class="undefined"> header {</span></span><br><span class="line"><span class="undefined"> position: aboluste;</span></span><br><span class="line"><span class="undefined"> height: 45px;</span></span><br><span class="line"><span class="undefined"> width: 100%;</span></span><br><span class="line"><span class="undefined"> }</span></span><br><span class="line"><span class="undefined"> #container {</span></span><br><span class="line"><span class="undefined"> position: absolute;</span></span><br><span class="line"><span class="undefined"> top: 45px;</span></span><br><span class="line"><span class="undefined"> bottom: 0;</span></span><br><span class="line"><span class="undefined"> width: 100%;</span></span><br><span class="line"><span class="undefined"> overflow: auto;</span></span><br><span class="line"><span class="undefined"> -webkit-overflow-scrolling: touch; }</span></span><br><span class="line"><span class="undefined"> </span><span class="tag"></<span class="name">style</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">header</span>></span><span class="tag"><<span class="name">input</span> <span class="attr">type</span>=<span class="string">"search"</span> <span class="attr">placeholder</span>=<span class="string">"请输入搜索词"</span> /></span><span class="tag"></<span class="name">header</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"container"</span>></span></span><br><span class="line"> ...</span><br><span class="line"> <span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><p>这种方案也有坑,主要表现在:<strong>当软键盘弹起时,用户一旦滚动界面,整个文档都会滚动(包括header、container),fixed的效果就没有了。</strong></p><p>还有一个更深的坑就是,在软键盘弹起的时候,往上滚动页面,header此时也会随着往上滚,<br>然后收起软键盘,container居然滚动不了(手指多移动几次后,才能正常滚动)。</p><p><em>Note: 这个问题不知道什么原因,以后有发现再更新本文。</em></p><p>综上,我还是喜欢使用第二种方案。</p><h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><ul><li><a href="http://remysharp.com/2012/05/24/issues-with-position-fixed-scrolling-on-ios/" target="_blank" rel="noopener">http://remysharp.com/2012/05/24/issues-with-position-fixed-scrolling-on-ios/</a></li></ul>]]></content>
<summary type="html">
<p>在ios5之前,我们如果要实现fixed导航条,我们得依赖iscroll来支持。</p>
<p>不过从ios5.1以来,fixed定位就已经支持了,但很遗憾,ios现在对它还只是半支持。</p>
<p>在大部分情况下,fixed表现得没有什么问题。</p>
<img src="/2014/08/19/ios-fixed-ding-wei-wen-ti/1.png">
<p>但是在某些情况下,会出现一些比较奇葩的问题,比如fixed元素中存在输入框子元素,这个时候就会跪了。</p>
</summary>
<category term="ios" scheme="http://hushicai.github.io/tags/ios/"/>
<category term="fixed" scheme="http://hushicai.github.io/tags/fixed/"/>
<category term="固定定位" scheme="http://hushicai.github.io/tags/%E5%9B%BA%E5%AE%9A%E5%AE%9A%E4%BD%8D/"/>
</entry>
<entry>
<title>v8的词法分析</title>
<link href="http://hushicai.github.io/2014/08/13/v8-de-ci-fa-fen-xi.html"/>
<id>http://hushicai.github.io/2014/08/13/v8-de-ci-fa-fen-xi.html</id>
<published>2014-08-12T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>本文将探讨v8是如何对utf8编码的js文件进行词法分析的!</p><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>v8提供了一个<code>Scanner</code>类作为词法分析器,在该类中有这么一个指针:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Utf16CharacterStream* stream_;</span><br></pre></td></tr></table></figure><p>这是个啥玩意?看一下源代码中对这个类的解释:</p><blockquote><p>// Buffered stream of UTF-16 code units, using an internal UTF-16 buffer.</p></blockquote><p>大概就是说,<code>Utf16CharacterStream</code>就是一个<strong>UTF-16代码单元</strong>的缓冲流。</p><p>啥是<strong>代码单元</strong>?v8的解释如下:</p><blockquote><p>// A code unit is a 16 bit value representing either a 16 bit code point<br>// or one part of a surrogate pair that make a single 21 bit code point.</p></blockquote><p>这就涉及到了unicode规范,在unicode字符集中,每个unicode字符都有一个唯一的<strong>代码点</strong>。</p><p>在utf8、utf16等编码形式中,代码点被映射到一个或者多个代码单元。</p><p>代码单元是各个编码形式中的最小单元,其大小:</p><ul><li>UTF-8 中的代码单元由 8 位组成。</li><li>UTF-16 中的代码单元由 16 位组成。</li></ul><p>每个代码点需要多少个代码单元呢?不同编码形式不一样:</p><ul><li>UTF-8中,每个代码点被映射到一个、两个、三个或者四个代码单元。</li><li>UTF-16中,值小于等于U+FFFF的代码点被映射到单个代码单元中,对于值大于U+FFFF的代码点,每个代码点需要两个代码单元。在UTF-16 中,这些代码单元对有一个独特的术语:“Unicode 代理对”。</li></ul><p>综上,我们可以知道<code>Utf16CharacterStream</code>中每一个UTF-16代码单元的含义:</p><blockquote><p>UTF-16中,一个代码单元要么是一个16位的代码点,要么是“Unicode代理对”中的一半,其中“unicode代码对”是一个21位的代码点。</p></blockquote><p>简而言之,<code>Utf16CharacterStream</code>中的每个代码单元,要么是一个独立的unicode字符,要么是一个unicode字符的一半(和下一个代码单元组合起来才能形成一个unicode字符)。</p><p>v8实际上就是基于utf16对输入字符序列进行词法分析的!这也是Ecmascript规范所要求的:</p><blockquote><p>ECMAScript 源代码文本使用 Unicode 3.0 或更高版本的字符编码的字符序列来表示。<br>符合 ECMAScript 的实现不要求对文本执行正规化,也不要求将其表现为像执行了正规化一样。<br>本规范的目的是假定 ECMAScript 源代码文本都是由16位代码单元组成的序列。<br>像这样包含16位代码单元序列的源文本可能不是有效的 UTF-16 字符编码。<br>如果实际源代码文本没有用16位代码单元形式的编码,那就必须把它看作已经转换为 UTF-16 一样处理。</p></blockquote><p>v8词法分析首先要做的是把输入字符序列转换成utf16 stream。</p><p>那如何把utf8编码的js文件转换成utf16 stream呢?</p><a id="more"></a><h2 id="字节流"><a href="#字节流" class="headerlink" title="字节流"></a>字节流</h2><p>首先,我们需要先获得utf8字节流:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 二进制方式打开</span></span><br><span class="line">FILE* file = fopen(filename, <span class="string">"rb"</span>); </span><br><span class="line"><span class="comment">// 移到文件尾</span></span><br><span class="line">fseek(file, <span class="number">0</span>, SEEK_END);</span><br><span class="line"><span class="comment">// 字节数</span></span><br><span class="line"><span class="keyword">int</span> file_size = ftell(file);</span><br><span class="line"><span class="comment">// 回到文件头</span></span><br><span class="line">rewind(file);</span><br><span class="line"><span class="comment">// 字节数组</span></span><br><span class="line">byte* chars = <span class="keyword">new</span> byte[file_size]; <span class="comment">// typedef unsigned char byte</span></span><br><span class="line">fread(chars, <span class="number">1</span>, file_size, file);</span><br><span class="line">chars[file_size] = <span class="number">0</span></span><br></pre></td></tr></table></figure><p>假设文件内容如下:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> 招聘(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> 信息 = <span class="string">"复合搜索部前端工程师"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>utf8字节流如下:</p><figure class="highlight plain"><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">66 75 6E 63 74 69 6F 6E 20 E6 8B 9B E8 81 98 28 29 20 7B 0A 20 20 20 20 76 61 72 20 E4 BF A1 E6 81 AF 20 3D 20 22 E5 A4</span><br><span class="line">8D E5 90 88 E6 90 9C E7 B4 A2 E9 83 A8 E5 89 8D E7 AB AF E5 B7 A5 E7 A8 8B E5 B8 88 22 3B 0A 7D 0A</span><br></pre></td></tr></table></figure><h2 id="转换"><a href="#转换" class="headerlink" title="转换"></a>转换</h2><p>现在,我们需要把utf8的字节流转换成utf16字符流,前面我们说了,词法分析器扫描的是<code>Utf16CharacterStream</code>类,不过这个类是一个抽象类,不能直接使用,<br>v8用了一个<code>BufferedUtf16CharacterStream</code>类来提供具体的功能,它继承至<code>Utf16CharacterStream</code>:</p><img src="/2014/08/13/v8-de-ci-fa-fen-xi/1.png"><p>这个<code>BufferedUtf16CharacterStream</code>提供了一个缓冲区<code>buffer_</code>,我们转换的时候,就是要向这个缓冲区填充字符。</p><p>具体的转换功能由一个叫<code>Utf8ToUtf16CharacterStream</code>的类提供,它继承至<code>BufferedUtf16CharacterStream</code>:</p><img src="/2014/08/13/v8-de-ci-fa-fen-xi/2.png"><p>基本用法:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// utf8字节流数组头部指针,指向第一个字节</span></span><br><span class="line"><span class="keyword">unsigned</span> <span class="keyword">char</span>* source_;</span><br><span class="line"><span class="comment">// 流指针</span></span><br><span class="line">BufferedUtf16CharacterStream* stream_ = <span class="keyword">new</span> Utf8ToUtf16CharacterStream(source_, length);</span><br></pre></td></tr></table></figure><p>在生成一个<code>BufferedUtf16CharacterStream</code>实例之时,在其构造函数中,会进行第一次字符填充。</p><p>在<code>Utf8ToUtf16CharacterStream::FillBuffer</code>方法中,有这么一段代码:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> (i < kBufferSize - <span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">if</span> (raw_data_pos_ == raw_data_length_) <span class="keyword">break</span>;</span><br><span class="line"> <span class="comment">// 取出当前字节</span></span><br><span class="line"> unibrow::uchar c = raw_data_[raw_data_pos_];</span><br><span class="line"> <span class="keyword">if</span> (c <= unibrow::Utf8::kMaxOneByteChar) {</span><br><span class="line"> <span class="comment">// 单字节字符</span></span><br><span class="line"> raw_data_pos_++;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 多字节字符,向前继续读字节,计算出字符</span></span><br><span class="line"> c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_,</span><br><span class="line"> raw_data_length_ - raw_data_pos_,</span><br><span class="line"> &raw_data_pos_);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (c > kMaxUtf16Character) {</span><br><span class="line"> <span class="comment">// 如果计算出来的字符超出U+FFFF,那就需要两个16位代码单元来表示,也就是我们前文所说的“Unicode代码对”</span></span><br><span class="line"> buffer_[i++] = unibrow::Utf16::LeadSurrogate(c);</span><br><span class="line"> buffer_[i++] = unibrow::Utf16::TrailSurrogate(c);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 如果计算出来的字符小于U+FFFF,那就直接填入buffer_</span></span><br><span class="line"> buffer_[i++] = <span class="keyword">static_cast</span><uc16>(c);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>最后的结果就是,<code>BufferedUtf16CharacterStream::buffer_</code>中的每一个元素都是一个16位代码单元,它要么是一个字符,要么是一个“Unicode代码对”的一半。</p><p>我们以上文得到的字节流为例,最后<code>BufferedUtf16CharacterStream::buffer_</code>中会类似这样:</p><img src="/2014/08/13/v8-de-ci-fa-fen-xi/3.png"><p>得到所有字符之后,接下来的工作就是扫描每个字符,分析出<code>Token</code>。</p><h2 id="扫描"><a href="#扫描" class="headerlink" title="扫描"></a>扫描</h2><p>v8扫描<code>BufferedUtf16CharacterStream::buffer_</code>中的每个代码单元,然后按照Ecmascript的文法产生式分析出所有Token。</p><p>我们先来看看<code>Scanner::Next</code>这个方法:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 是否ASCII字符</span></span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">static_cast</span><<span class="keyword">unsigned</span>>(c0_) <= <span class="number">0x7f</span>) {</span><br><span class="line"> <span class="comment">// 从`one_char_tokens`中取出该Token</span></span><br><span class="line"> Token::Value token = <span class="keyword">static_cast</span><Token::Value>(one_char_tokens[c0_]);</span><br><span class="line"> <span class="comment">// 如果取出来的Token不是ILLEGAL的话,返回该Token</span></span><br><span class="line"> <span class="keyword">if</span> (token != Token::ILLEGAL) {</span><br><span class="line"> <span class="keyword">int</span> pos = source_pos();</span><br><span class="line"> next_.token = token;</span><br><span class="line"> next_.location.beg_pos = pos;</span><br><span class="line"> next_.location.end_pos = pos + <span class="number">1</span>;</span><br><span class="line"> Advance();</span><br><span class="line"> <span class="keyword">return</span> current_.token;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 否则继续扫描</span></span><br><span class="line">Scan();</span><br><span class="line"><span class="keyword">return</span> current_.token;</span><br></pre></td></tr></table></figure><p>我们注意到上面代码中的<code>one_char_tokens</code>,这货是啥?它其实就是个大小为128的数组,其中元素大部分是Token::ILLEGAL,只有几个有效的Token:</p><ul><li>Token::LPAREN “(“</li><li>Token::RPAREN “)”</li><li>Token::COMMA “,”</li><li>Token::COLON “:”</li><li>Token::SEMICOLON “;”</li><li>Token::CONDITIONAL “?”</li><li>Token::LBRACK “[“</li><li>Token::RBRACK “]”</li><li>Token::LBRACE “{“</li><li>Token::RBRACE “}”</li><li>Token::BIT_NOT “~”</li></ul><p>如果没匹配到<code>one_char_tokens</code>,则调用<code>Scanner::Scan</code>继续扫描:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">switch</span>(c0_) {</span><br><span class="line"> <span class="comment">// 匹配各种常见的字符...</span></span><br><span class="line"> <span class="keyword">case</span> <span class="string">' '</span></span><br><span class="line"> <span class="keyword">case</span> <span class="string">'\t'</span></span><br><span class="line"> <span class="keyword">case</span> <span class="string">'='</span></span><br><span class="line"> <span class="keyword">case</span> <span class="string">'~'</span></span><br><span class="line"> ...</span><br><span class="line"> <span class="keyword">default</span>:</span><br><span class="line"> <span class="comment">// 匹配identifier或者keyword等</span></span><br><span class="line"> <span class="keyword">if</span> (unicode_cache_->IsIdentifierStart(c0_)) {</span><br><span class="line"> token = ScanIdentifierOrKeyword();</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (IsDecimalDigit(c0_)) {</span><br><span class="line"> token = ScanNumber(<span class="literal">false</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (SkipWhiteSpace()) {</span><br><span class="line"> token = Token::WHITESPACE;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (c0_ < <span class="number">0</span>) {</span><br><span class="line"> token = Token::EOS;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> token = Select(Token::ILLEGAL);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>注意到上面的<code>ScanIdentifierOrKeyword</code>方法,这个方法是Token分析的核心,顾名思义,它就是用来分析<code>identifier</code>或者<code>keyword</code>的:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 字符链</span></span><br><span class="line"><span class="comment">// 比如`name`这样一个Token,有4个字符,这4个字符就连成了一个LiteralScope</span></span><br><span class="line"><span class="comment">// 当扫描完这4个字符后,会调用`LiteralScope::Complete`,这样就完成了一个Token的分析</span></span><br><span class="line"><span class="function">LiteralScope <span class="title">literal</span><span class="params">(<span class="keyword">this</span>)</span></span>;</span><br><span class="line"><span class="comment">// 扫描unicode转义字符</span></span><br><span class="line"><span class="keyword">if</span> (c0_ == <span class="string">'\\'</span>) {</span><br><span class="line"> uc32 c = ScanIdentifierUnicodeEscape();</span><br><span class="line"> <span class="comment">// Only allow legal identifier start characters.</span></span><br><span class="line"> <span class="keyword">if</span> (c < <span class="number">0</span> ||</span><br><span class="line"> c == <span class="string">'\\'</span> || <span class="comment">// No recursive escapes.</span></span><br><span class="line"> !unicode_cache_->IsIdentifierStart(c)) {</span><br><span class="line"> <span class="keyword">return</span> Token::ILLEGAL;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// \u0020</span></span><br><span class="line"> AddLiteralChar(c);</span><br><span class="line"> <span class="keyword">return</span> ScanIdentifierSuffix(&literal);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">uc32 first_char = c0_;</span><br><span class="line">Advance();</span><br><span class="line">AddLiteralChar(first_char);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 向前扫描字符,直至遇到一个不是有效的identifier字符为止,比如空格、(、[等</span></span><br><span class="line"><span class="keyword">while</span> (unicode_cache_->IsIdentifierPart(c0_)) {</span><br><span class="line"> <span class="keyword">if</span> (c0_ != <span class="string">'\\'</span>) {</span><br><span class="line"> uc32 next_char = c0_;</span><br><span class="line"> Advance();</span><br><span class="line"> AddLiteralChar(next_char);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Fallthrough if no longer able to complete keyword.</span></span><br><span class="line"> <span class="keyword">return</span> ScanIdentifierSuffix(&literal);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 结束一个字符链,即已经扫描出了一个identifier或者keyword</span></span><br><span class="line">literal.Complete();</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (next_.literal_chars->is_one_byte()) {</span><br><span class="line"> Vector<<span class="keyword">const</span> <span class="keyword">uint8_t</span>> chars = next_.literal_chars->one_byte_literal();</span><br><span class="line"> <span class="comment">// 判断是标志符还是关键词</span></span><br><span class="line"> <span class="comment">// v8内部定义了一系列关键词matcher,能match到的就是关键词,否则就是标志符</span></span><br><span class="line"> <span class="keyword">return</span> KeywordOrIdentifierToken(chars.start(),</span><br><span class="line"> chars.length(),</span><br><span class="line"> harmony_scoping_,</span><br><span class="line"> harmony_modules_);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> Token::IDENTIFIER;</span><br></pre></td></tr></table></figure><p>我们以前文的<code>buffer_</code>字符数组为例,经过<code>Scanner</code>扫描后,会产生类似这样的结果:</p><img src="/2014/08/13/v8-de-ci-fa-fen-xi/4.png"><p>最后,对整个文件内容扫描完的结果大概就类似这样:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">No of tokens: 12</span><br><span class="line">=> FUNCTION at (0, 8)</span><br><span class="line">=> IDENTIFIER at (9, 11)</span><br><span class="line">=> LPAREN at (11, 12)</span><br><span class="line">=> RPAREN at (12, 13)</span><br><span class="line">=> LBRACE at (14, 15)</span><br><span class="line">=> VAR at (20, 23)</span><br><span class="line">=> IDENTIFIER at (24, 26)</span><br><span class="line">=> ASSIGN at (27, 28)</span><br><span class="line">=> STRING at (29, 41)</span><br><span class="line">=> SEMICOLON at (41, 42)</span><br><span class="line">=> RBRACE at (43, 44)</span><br><span class="line">=> EOS at (45, 45)</span><br></pre></td></tr></table></figure><p>在utf8编码的情况下,v8整个词法分析过程,大概就是这样,当然实际过程中,还有很多细节问题需要处理,比如跳过js注释、html注释<br>、扫描十六进制字符、8进制字符、unicode转义字符等等</p><p>这就是本人粗略看了v8词法分析源码之后的一点理解,欢迎各路大神点评!</p>]]></content>
<summary type="html">
<p>本文将探讨v8是如何对utf8编码的js文件进行词法分析的!</p>
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>v8提供了一个<code>Scanner</code>类作为词法分析器,在该类中有这么一个指针:</p>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Utf16CharacterStream* stream_;</span><br></pre></td></tr></table></figure>
<p>这是个啥玩意?看一下源代码中对这个类的解释:</p>
<blockquote>
<p>// Buffered stream of UTF-16 code units, using an internal UTF-16 buffer.</p>
</blockquote>
<p>大概就是说,<code>Utf16CharacterStream</code>就是一个<strong>UTF-16代码单元</strong>的缓冲流。</p>
<p>啥是<strong>代码单元</strong>?v8的解释如下:</p>
<blockquote>
<p>// A code unit is a 16 bit value representing either a 16 bit code point<br>// or one part of a surrogate pair that make a single 21 bit code point.</p>
</blockquote>
<p>这就涉及到了unicode规范,在unicode字符集中,每个unicode字符都有一个唯一的<strong>代码点</strong>。</p>
<p>在utf8、utf16等编码形式中,代码点被映射到一个或者多个代码单元。</p>
<p>代码单元是各个编码形式中的最小单元,其大小:</p>
<ul>
<li>UTF-8 中的代码单元由 8 位组成。</li>
<li>UTF-16 中的代码单元由 16 位组成。</li>
</ul>
<p>每个代码点需要多少个代码单元呢?不同编码形式不一样:</p>
<ul>
<li>UTF-8中,每个代码点被映射到一个、两个、三个或者四个代码单元。</li>
<li>UTF-16中,值小于等于U+FFFF的代码点被映射到单个代码单元中,对于值大于U+FFFF的代码点,每个代码点需要两个代码单元。在UTF-16 中,这些代码单元对有一个独特的术语:“Unicode 代理对”。</li>
</ul>
<p>综上,我们可以知道<code>Utf16CharacterStream</code>中每一个UTF-16代码单元的含义:</p>
<blockquote>
<p>UTF-16中,一个代码单元要么是一个16位的代码点,要么是“Unicode代理对”中的一半,其中“unicode代码对”是一个21位的代码点。</p>
</blockquote>
<p>简而言之,<code>Utf16CharacterStream</code>中的每个代码单元,要么是一个独立的unicode字符,要么是一个unicode字符的一半(和下一个代码单元组合起来才能形成一个unicode字符)。</p>
<p>v8实际上就是基于utf16对输入字符序列进行词法分析的!这也是Ecmascript规范所要求的:</p>
<blockquote>
<p>ECMAScript 源代码文本使用 Unicode 3.0 或更高版本的字符编码的字符序列来表示。<br>符合 ECMAScript 的实现不要求对文本执行正规化,也不要求将其表现为像执行了正规化一样。<br>本规范的目的是假定 ECMAScript 源代码文本都是由16位代码单元组成的序列。<br>像这样包含16位代码单元序列的源文本可能不是有效的 UTF-16 字符编码。<br>如果实际源代码文本没有用16位代码单元形式的编码,那就必须把它看作已经转换为 UTF-16 一样处理。</p>
</blockquote>
<p>v8词法分析首先要做的是把输入字符序列转换成utf16 stream。</p>
<p>那如何把utf8编码的js文件转换成utf16 stream呢?</p>
</summary>
<category term="v8" scheme="http://hushicai.github.io/tags/v8/"/>
<category term="token" scheme="http://hushicai.github.io/tags/token/"/>
<category term="词法分析" scheme="http://hushicai.github.io/tags/%E8%AF%8D%E6%B3%95%E5%88%86%E6%9E%90/"/>
<category term="源代码" scheme="http://hushicai.github.io/tags/%E6%BA%90%E4%BB%A3%E7%A0%81/"/>
</entry>
<entry>
<title>mac osx下编译v8</title>
<link href="http://hushicai.github.io/2014/08/10/mac-osx-xia-bian-yi-v8.html"/>
<id>http://hushicai.github.io/2014/08/10/mac-osx-xia-bian-yi-v8.html</id>
<published>2014-08-09T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>v8相信大家都不陌生,本文将介绍一下,如何在mac osx下编译v8,并用一个例子来试验编译结果。</p><h2 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h2><p>首先获取一下源代码,v8在github上有镜像,可以直接clone github上的。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/v8/v8.git</span><br></pre></td></tr></table></figure><p>代码量较大,请耐心等待…</p><p>下载完成后,我们还需要下载编译前的依赖。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make builddeps</span><br></pre></td></tr></table></figure><p><em>Note: 以上命令都比较悲剧,因为要跨越我朝的墙…建议使用vpn吧,用goagent也可以,不过会很慢。</em></p><p>依赖下载完成之后,我们就可以正式build了:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make</span><br></pre></td></tr></table></figure><p>更多编译选项,请查看<a href="https://code.google.com/p/v8/wiki/BuildingWithGYP" target="_blank" rel="noopener">官网</a>。</p><a id="more"></a><p>编译完成之后,在out目录下会生成类似以下目录:</p><ul><li><code>out/ia32.release</code></li><li><code>out/ia32.debug</code></li><li><code>out/x64.release</code></li><li><code>out/x64.debug</code></li><li>…</li></ul><p>按照平台划分,我的机器是x64,debug与release也有一些区别,比如log以及一些新特性等</p><p>我们以<code>x64.debug</code>为例,在该目录下,有一些可执行文件,比如<code>d8</code>,这个可执行文件可用来直接在命令行下运行javascript(当然,不包括dom、bom等)。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./d8</span><br></pre></td></tr></table></figure><p>运行d8后,就会进入一个可交互的shell环境,可执行js,例如:</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">d8> 1 + 2</span><br><span class="line">3</span><br></pre></td></tr></table></figure><h2 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h2><p>在<code>out/x64.debug</code>下,除了一些可执行文件外,还生成了一些静态链接库,比如:</p><ul><li><code>out/x64.debug/libv8_base.a</code></li><li><code>out/x64.debug/libv8_libbase.a</code></li><li>…</li></ul><p>这些文件在编译v8一些例子的时候,需要链接进来。</p><p>我们来编译一下官网的Hello World例子,代码如下:</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><v8.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> v8;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span>* argv[])</span> </span>{</span><br><span class="line"> <span class="comment">// Create a new Isolate and make it the current one.</span></span><br><span class="line"> Isolate* isolate = Isolate::New();</span><br><span class="line"> Isolate::<span class="function">Scope <span class="title">isolate_scope</span><span class="params">(isolate)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Create a stack-allocated handle scope.</span></span><br><span class="line"> <span class="function">HandleScope <span class="title">handle_scope</span><span class="params">(isolate)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Create a new context.</span></span><br><span class="line"> Local<Context> context = Context::New(isolate);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Enter the context for compiling and running the hello world script.</span></span><br><span class="line"> Context::<span class="function">Scope <span class="title">context_scope</span><span class="params">(context)</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Create a string containing the JavaScript source code.</span></span><br><span class="line"> Local<String> source = String::NewFromUtf8(isolate, <span class="string">"'Hello' + ', World!'"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Compile the source code.</span></span><br><span class="line"> Local<Script> script = Script::Compile(source);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Run the script to get the result.</span></span><br><span class="line"> Local<Value> result = script->Run();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Convert the result to an UTF8 string and print it.</span></span><br><span class="line"> String::<span class="function">Utf8Value <span class="title">utf8</span><span class="params">(result)</span></span>;</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"%s\n"</span>, *utf8);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>链接静态库,编译HelloWorld.cc:</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></pre></td><td class="code"><pre><span class="line">clang++ -I./include samples/HelloWorld.cc -o ./out/HelloWorld \</span><br><span class="line"> -Wl, ./out/x64.debug/libv8_base.a \</span><br><span class="line"> -Wl, ./out/x64.debug/libv8_libbase.a \</span><br><span class="line"> -Wl, ./out/x64.debug/libicui18n.a \</span><br><span class="line"> -Wl, ./out/x64.debug/libicudata.a \</span><br><span class="line"> -Wl, ./out/x64.debug/libicuuc.a \</span><br><span class="line"> -Wl, ./out/x64.debug/libv8_snapshot.a \</span><br><span class="line"> -stdlib=libstdc++</span><br></pre></td></tr></table></figure><p><strong>注意最后的<code>stdlib</code>参数,最新版的mac使用的是llvm编译器,其默认的标准库是<code>libc++</code>,但v8依赖的是<code>libstdc++</code>。</strong></p><p>编译完成后,在out目录下就生成了可执行文件HelloWorld:</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">$ ./HelloWorld</span><br><span class="line">Hello World!</span><br></pre></td></tr></table></figure><p>大功告成!</p><p>网上其实有很多类似的v8编译博文,不过大部分都是比较老的文章,最新版的编译方式还不大一样,希望本文对您有所帮助!</p>]]></content>
<summary type="html">
<p>v8相信大家都不陌生,本文将介绍一下,如何在mac osx下编译v8,并用一个例子来试验编译结果。</p>
<h2 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h2><p>首先获取一下源代码,v8在github上有镜像,可以直接clone github上的。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/v8/v8.git</span><br></pre></td></tr></table></figure>
<p>代码量较大,请耐心等待…</p>
<p>下载完成后,我们还需要下载编译前的依赖。</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make builddeps</span><br></pre></td></tr></table></figure>
<p><em>Note: 以上命令都比较悲剧,因为要跨越我朝的墙…建议使用vpn吧,用goagent也可以,不过会很慢。</em></p>
<p>依赖下载完成之后,我们就可以正式build了:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make</span><br></pre></td></tr></table></figure>
<p>更多编译选项,请查看<a href="https://code.google.com/p/v8/wiki/BuildingWithGYP" target="_blank" rel="noopener">官网</a>。</p>
</summary>
<category term="mac osx" scheme="http://hushicai.github.io/tags/mac-osx/"/>
<category term="v8" scheme="http://hushicai.github.io/tags/v8/"/>
</entry>
<entry>
<title>关于页面首屏时间</title>
<link href="http://hushicai.github.io/2014/04/19/guan-yu-ye-mian-shou-ping-shi-jian.html"/>
<id>http://hushicai.github.io/2014/04/19/guan-yu-ye-mian-shou-ping-shi-jian.html</id>
<published>2014-04-18T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>什么是首屏?英文叫<code>above the fold</code>,google一下<code>above the fold</code>,可以发现在维基百科上有专门的<a href="http://en.wikipedia.org/wiki/Above_the_fold" target="_blank" rel="noopener">条目</a> 。</p><p>正如维基百科上所说,<code>above the fold</code>这个概念最早出现在报纸上,也就是我们通常所说的报纸头条!</p><p>这个概念后来被沿用到web上,web中的<code>above the fold</code>,维基百科是这么解释的:</p><blockquote><p>Above the fold is also used in website design (along with “above the scroll”) to refer to the portion of the webpage<br>that is visible without scrolling. As screen sizes vary drastically there is no set definition for the number of<br>pixels that define the fold. This is because different screen resolutions will show different portions of the website<br>without scrolling. Further complicating matters, many websites adjust their layout based on the size of the browser<br>window, such that the fold is not a static feature of the page.</p></blockquote><p>如上文所说,web中的首屏不同于报纸头条,它的区域是动态的,因为用户的屏幕分辨率是不同的。</p><p>那我们应该怎么确定这个首屏范围呢?这个范围需要根据用户的浏览器分辨率数据来制定。</p><p>在web中,一般我们只需要敲定一个高度,然后得到一条<em>首屏线</em>。</p><p>首屏线以上的内容通常是一个站点想优先展现给用户的东西,它能不能及时展示是能不能留住用户一个非常重要的因素。</p><a id="more"></a><h2 id="首屏时间"><a href="#首屏时间" class="headerlink" title="首屏时间"></a>首屏时间</h2><p>用户访问一个站点时,浏览器会首先发出一个请求,请求该html文档,浏览器接收到文档内容时,开始解析并渲染到窗口上。</p><p>在这个过程中,有两个时间点比较重要:</p><ul><li><code>Time Of First Byte</code></li><li><code>Start Render Time</code></li></ul><p>这两个时间点将首屏时间分为了三段,如下图所示:</p><img src="/2014/04/19/guan-yu-ye-mian-shou-ping-shi-jian/above-the-fold.png"><p>通过这两个时间点,我们可以更好地分析首屏时间的瓶颈到底在哪个阶段中。</p><h3 id="Time-Of-First-Byte"><a href="#Time-Of-First-Byte" class="headerlink" title="Time Of First Byte"></a>Time Of First Byte</h3><p>浏览器请求一个文档,需要经过blocking、proxying、dns<br>lookup、connecting、sending、waiting等过程,首字节时间就是用来衡量这些过程性能的一个关键指标。</p><p>首字节时间越长,浏览器就越晚解析文档,首屏时间就越长。</p><p>在HTML5 performance API中提供了这个时间点。</p><p>如果首字节时间越长,那么瓶颈应该应该是存在于网络、后端程序等方面。</p><h3 id="Start-Render-Time"><a href="#Start-Render-Time" class="headerlink" title="Start Render Time"></a>Start Render Time</h3><p><code>Start Render Time</code>是指用户屏幕刚开始显示某些内容的时刻。</p><p>浏览器屏幕刚开始是一大片空白,绘制时会发生一些变化,可能是显示背景、logo或者文字等。</p><p>看过浏览器工作原理的小伙伴们应该都知道,非可视化的DOM元素不会显示到窗口中,例如head,这就意味着浏览器在绘制之前,<br>至少需要先解析完head元素中的内容。</p><p>一般情况下,只要文档中的css资源准备就绪,浏览器就可以开始绘制,而通常我们的css文件都会放在head中,<br>因此,我们可以认为浏览器开始渲染body标签或者解析玩head标签的时刻就是<code>Start Render Time</code>,<br>利用这一点,我们可以在body标签开始处或者head标签结束处埋入一段脚本,用以获取这个<code>Start Render Time</code>。</p><p><em>PS:请参考<a href="http://www.html5rocks.com/zh/tutorials/internals/howbrowserswork/" target="_blank" rel="noopener">浏览器的工作原理</a>。</em></p><p>这个时间减去首字节时间,就是head标签的解析时间,从而我们就能知道head标签中的内容是否拖长了首屏时间。</p><p><em>Note: 通常这个时间也叫白屏时间或者First Paint Time等。</em></p><h3 id="首屏渲染时间"><a href="#首屏渲染时间" class="headerlink" title="首屏渲染时间"></a>首屏渲染时间</h3><p>当我们指定了一个首屏线之后,首屏线以上的内容就是我们所说的首屏,这个区域本身也需要时间来渲染的。</p><p>这个区域的资源越多(css、js、img等),其渲染时间就越长,首屏时间也就越长。</p><h2 id="如何测量首屏时间"><a href="#如何测量首屏时间" class="headerlink" title="如何测量首屏时间"></a>如何测量首屏时间</h2><p>前面提到web中的首屏需要根据用户屏幕分辨率数据确定一个首屏线,首屏线以上的内容就是首屏。</p><p>怎么测量首屏花费了多少时间呢?</p><p>现在大部分浏览器端的做法都是在首屏线处埋点标记,然后计算标记点之前所有图片加载完成的时间,把这个时间作为首屏时间。</p><p>很显然这种做法,误差不小,但是貌似没什么好办法。</p><p>也有人提到用<code>phantomjs</code>、<code>berserkjs</code>等来做,不知道是否可行,待验证。</p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>综上,如果我们发现站点的首屏时间很长,应该从以下三方面逐步进行排查:</p><ul><li><code>Time Of First Byte</code>,通常可以通过cdn、cache、chunked、提升后台程序性能等手段来优化;</li><li><code>Start Render Time</code>,通常是避免在head中使用过多资源,比如将js放到body结束处等;</li><li>首屏时间,通常做法是减少首屏区域内容,或者用lazyload等手段来优化;</li></ul><p>如果你想监控站点的性能,可以使用yslow、pagespeed等工具</p><h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><ul><li><a href="http://www.websiteoptimization.com/speed/tweak/time-to-first-byte/" target="_blank" rel="noopener">http://www.websiteoptimization.com/speed/tweak/time-to-first-byte/</a></li><li><a href="http://www.websiteoptimization.com/speed/tweak/start-render/" target="_blank" rel="noopener">http://www.websiteoptimization.com/speed/tweak/start-render/</a></li><li><a href="http://www.webpagetest.org/forums/showthread.php?tid=15" target="_blank" rel="noopener">http://www.webpagetest.org/forums/showthread.php?tid=15</a></li><li><a href="https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html" target="_blank" rel="noopener">https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html</a></li></ul>]]></content>
<summary type="html">
<p>什么是首屏?英文叫<code>above the fold</code>,google一下<code>above the fold</code>,可以发现在维基百科上有专门的<a href="http://en.wikipedia.org/wiki/Above_the_fold" target="_blank" rel="noopener">条目</a> 。</p>
<p>正如维基百科上所说,<code>above the fold</code>这个概念最早出现在报纸上,也就是我们通常所说的报纸头条!</p>
<p>这个概念后来被沿用到web上,web中的<code>above the fold</code>,维基百科是这么解释的:</p>
<blockquote>
<p>Above the fold is also used in website design (along with “above the scroll”) to refer to the portion of the webpage<br>that is visible without scrolling. As screen sizes vary drastically there is no set definition for the number of<br>pixels that define the fold. This is because different screen resolutions will show different portions of the website<br>without scrolling. Further complicating matters, many websites adjust their layout based on the size of the browser<br>window, such that the fold is not a static feature of the page.</p>
</blockquote>
<p>如上文所说,web中的首屏不同于报纸头条,它的区域是动态的,因为用户的屏幕分辨率是不同的。</p>
<p>那我们应该怎么确定这个首屏范围呢?这个范围需要根据用户的浏览器分辨率数据来制定。</p>
<p>在web中,一般我们只需要敲定一个高度,然后得到一条<em>首屏线</em>。</p>
<p>首屏线以上的内容通常是一个站点想优先展现给用户的东西,它能不能及时展示是能不能留住用户一个非常重要的因素。</p>
</summary>
<category term="首屏时间" scheme="http://hushicai.github.io/tags/%E9%A6%96%E5%B1%8F%E6%97%B6%E9%97%B4/"/>
<category term="首字节时间" scheme="http://hushicai.github.io/tags/%E9%A6%96%E5%AD%97%E8%8A%82%E6%97%B6%E9%97%B4/"/>
<category term="开始渲染时间" scheme="http://hushicai.github.io/tags/%E5%BC%80%E5%A7%8B%E6%B8%B2%E6%9F%93%E6%97%B6%E9%97%B4/"/>
<category term="白屏时间" scheme="http://hushicai.github.io/tags/%E7%99%BD%E5%B1%8F%E6%97%B6%E9%97%B4/"/>
<category term="above the fold" scheme="http://hushicai.github.io/tags/above-the-fold/"/>
<category term="Time Of First Byte" scheme="http://hushicai.github.io/tags/Time-Of-First-Byte/"/>
<category term="Start Render Time" scheme="http://hushicai.github.io/tags/Start-Render-Time/"/>
</entry>
<entry>
<title>mac osx命令行下利用goagent作代理</title>
<link href="http://hushicai.github.io/2014/04/08/mac-osx-ming-ling-xing-xia-li-yong-goagent-zuo-dai-li.html"/>
<id>http://hushicai.github.io/2014/04/08/mac-osx-ming-ling-xing-xia-li-yong-goagent-zuo-dai-li.html</id>
<published>2014-04-07T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>今天在使用brew安装vim7.4时,遭遇了伟大的GFW墙:LuaJit这货总是下载不下来。</p><p>于是就开始找代理了,但是手头上只有goagent,没有vpn,咋整?</p><p>偶然在一篇文章上发现了curl、wget等http应用程序会调用<code>http_proxy</code>和<code>https_proxy</code>这两环境变量进行代理,于是我就尝试设置一下:</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"><span class="built_in">export</span> http_proxy=http://127.0.0.1:8087</span><br><span class="line"><span class="built_in">export</span> https_proxy=<span class="variable">$http_proxy</span></span><br></pre></td></tr></table></figure><p><em>PS:别用<code>ping</code>对以上代理进行测试,不管用。</em></p><p>试着重新安装vim7.4,果然不再被墙,成功下载了!并且在goagent的log上也可以观察到:</p><pre><code>INFO - [Apr 8 16:13:33] 127.0.0.1:60865 "GAE GET http://luajit.org/download/LuaJIT-2.0.3.tar.gz HTTP/1.1" 206 271735 </code></pre><p>这说明brew的curl确实使用了我刚才设置的代理。</p><p>大伙可以在<code>~/.zshrc</code>或者<code>~/.bash_profile</code>中添加这样的alias:</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"><span class="built_in">alias</span> goproxy=<span class="string">'export http_proxy=http://127.0.0.1:8087 https_proxy=http://127.0.0.1:8087'</span></span><br><span class="line"><span class="built_in">alias</span> disproxy=<span class="string">'unset http_proxy https_proxy'</span></span><br></pre></td></tr></table></figure><p>这样下次就可以很方便地切换proxy了!</p>]]></content>
<summary type="html">
<p>今天在使用brew安装vim7.4时,遭遇了伟大的GFW墙:LuaJit这货总是下载不下来。</p>
<p>于是就开始找代理了,但是手头上只有goagent,没有vpn,咋整?</p>
<p>偶然在一篇文章上发现了curl、wget等http应用程序会调用<code>htt
</summary>
<category term="brew install" scheme="http://hushicai.github.io/tags/brew-install/"/>
<category term="墙" scheme="http://hushicai.github.io/tags/%E5%A2%99/"/>
<category term="http_proxy" scheme="http://hushicai.github.io/tags/http-proxy/"/>
<category term="https_proxy" scheme="http://hushicai.github.io/tags/https-proxy/"/>
</entry>
<entry>
<title>mac osx下无法安装brew问题</title>
<link href="http://hushicai.github.io/2014/04/07/mac-osx-xia-wu-fa-an-zhuang-brew-wen-ti.html"/>
<id>http://hushicai.github.io/2014/04/07/mac-osx-xia-wu-fa-an-zhuang-brew-wen-ti.html</id>
<published>2014-04-06T16:00:00.000Z</published>
<updated>2018-07-06T18:18:49.000Z</updated>
<content type="html"><![CDATA[<p>今天很倒霉,本来想update brew的,结果update半天没成功,一怒之下把它删了重装,悲剧就从删除时刻开始上演!!!</p><p>捣鼓了一个下午,始终没法重新装上<code>brew</code>,没道理啊,我就按照官网上干的:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"</span><br></pre></td></tr></table></figure><p>但是执行完以上命令之后,却卡住了:</p><ul><li>命令上一直显示<code>Downloading and installing Homebrew...</code></li><li>经过一段漫长的时间后,会出现<code>unable to fetch https://github.com/Homebrew/homebrew.git</code></li></ul><p>研究很久,没有找到原因,直到晚上的时候,发现python的<code>https_open</code>方法也挂了?这就很不寻常了。</p><p>很有可能系统的ssl有问题!查看了系统的<code>openssl</code>版本,发现不是最新的,我当场就决定先更新一下<code>openssl</code>试试。</p><a id="more"></a><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">curl --remote-name http://www.openssl.org/<span class="built_in">source</span>/openssl-1.0.1f.tar.gz</span><br><span class="line">tar -xzvf openssl-1.0.1f.tar.gz</span><br><span class="line"><span class="built_in">cd</span> openssl-1.0.1f</span><br><span class="line"></span><br><span class="line">./configure darwin64-x86_64-cc --prefix=/usr <span class="comment"># 直接覆盖系统的openssl,所以指定prefix=/usr</span></span><br><span class="line">make</span><br><span class="line">sudo make install</span><br></pre></td></tr></table></figure><p>安装完成之后,先试一把<code>https_open</code>,居然没问题了!!立马接着再试试安装<code>brew</code>,尼玛,终于不卡在<code>downloading</code>那了!</p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>看了<code>brew</code>的安装脚本,它实际上就是通过git安装到本地的,所以下次如果遇到诸如git<br>clone不了https协议打头的仓库地址,就得先查查系统的<code>openssl</code>有没有问题!</p><p>当然也有可能是被GFW墙了!如果被墙,那就只能想办法搞个vpn了!</p>]]></content>
<summary type="html">
<p>今天很倒霉,本来想update brew的,结果update半天没成功,一怒之下把它删了重装,悲剧就从删除时刻开始上演!!!</p>
<p>捣鼓了一个下午,始终没法重新装上<code>brew</code>,没道理啊,我就按照官网上干的:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ruby -e &quot;$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)&quot;</span><br></pre></td></tr></table></figure>
<p>但是执行完以上命令之后,却卡住了:</p>
<ul>
<li>命令上一直显示<code>Downloading and installing Homebrew...</code></li>
<li>经过一段漫长的时间后,会出现<code>unable to fetch https://github.com/Homebrew/homebrew.git</code></li>
</ul>
<p>研究很久,没有找到原因,直到晚上的时候,发现python的<code>https_open</code>方法也挂了?这就很不寻常了。</p>
<p>很有可能系统的ssl有问题!查看了系统的<code>openssl</code>版本,发现不是最新的,我当场就决定先更新一下<code>openssl</code>试试。</p>
</summary>
<category term="mac osx" scheme="http://hushicai.github.io/tags/mac-osx/"/>
<category term="brew" scheme="http://hushicai.github.io/tags/brew/"/>
<category term="openssl" scheme="http://hushicai.github.io/tags/openssl/"/>
<category term="无法安装" scheme="http://hushicai.github.io/tags/%E6%97%A0%E6%B3%95%E5%AE%89%E8%A3%85/"/>
<category term="卡住" scheme="http://hushicai.github.io/tags/%E5%8D%A1%E4%BD%8F/"/>
</entry>
</feed>