-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
1519 lines (859 loc) · 121 KB
/
index.html
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
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html class="theme-next mist use-motion">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link href="/vendors/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
<link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
<link href="/vendors/font-awesome/css/font-awesome.min.css?v=4.4.0" rel="stylesheet" type="text/css" />
<link href="/css/main.css?v=5.0.1" rel="stylesheet" type="text/css" />
<meta name="keywords" content="Hexo, NexT" />
<link rel="shortcut icon" type="image/x-icon" href="/blog.ico?v=5.0.1" />
<meta name="description" content="既然选择了远方,便只顾风雨兼程personal blog">
<meta property="og:type" content="website">
<meta property="og:title" content="icetower">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="icetower">
<meta property="og:description" content="既然选择了远方,便只顾风雨兼程personal blog">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="icetower">
<meta name="twitter:description" content="既然选择了远方,便只顾风雨兼程personal blog">
<script type="text/javascript" id="hexo.configuration">
var NexT = window.NexT || {};
var CONFIG = {
scheme: 'Mist',
sidebar: {"position":"left","display":"post"},
fancybox: true,
motion: true,
duoshuo: {
userId: 0,
author: '博主'
}
};
</script>
<title> icetower </title>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<script type="text/javascript">
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?9b88e5171ec44a2e79c0192d9a90f7cb";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<div class="container one-collumn sidebar-position-left
page-home
">
<div class="headband"></div>
<!--- add Fork me on Github -->
<a href="https://github.com/yanghcc"><img style="position: absolute; top: 0; left: 0; border: 0;" src="https://camo.githubusercontent.com/c6625ac1f3ee0a12250227cf83ce904423abf351/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f677261795f3664366436642e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_left_gray_6d6d6d.png"></a>
<!--- add Fork me on Github -->
<header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-meta ">
<div class="custom-logo-site-title">
<a href="/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<span class="site-title">icetower</span>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<p class="site-subtitle">静下心好好工作,好好生活</p>
</div>
<div class="site-nav-toggle">
<button>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
<span class="btn-bar"></span>
</button>
</div>
<nav class="site-nav">
<ul id="menu" class="menu">
<li class="menu-item menu-item-home">
<a href="/" rel="section">
<i class="menu-item-icon fa fa-fw fa-home"></i> <br />
首页
</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/archives" rel="section">
<i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
归档
</a>
</li>
<li class="menu-item menu-item-css">
<a href="/css" rel="section">
<i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br />
CSS笔记
</a>
</li>
<li class="menu-item menu-item-article">
<a href="/article" rel="section">
<i class="menu-item-icon fa fa-fw fa-th"></i> <br />
文章
</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/tags" rel="section">
<i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
标签
</a>
</li>
<li class="menu-item menu-item-search">
<a href="#" class="popup-trigger">
<i class="menu-item-icon fa fa-search fa-fw"></i> <br />
搜索
</a>
</li>
</ul>
<div class="site-search">
<div class="popup">
<span class="search-icon fa fa-search"></span>
<input type="text" id="local-search-input">
<div id="local-search-result"></div>
<span class="popup-btn-close">close</span>
</div>
</div>
</nav>
</div>
</header>
<main id="main" class="main">
<div class="main-inner">
<div class="content-wrap">
<div id="content" class="content">
<section id="posts" class="posts-expand">
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/03/09/interviewTest/" itemprop="url">
使用vuejs开发的一个面试页面
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2017-03-09T19:17:02+08:00" content="2017-03-09">
2017-03-09
</time>
</span>
<span class="post-category" >
|
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="https://schema.org/Thing">
<a href="/categories/前端框架/" itemprop="url" rel="index">
<span itemprop="name">前端框架</span>
</a>
</span>
</span>
<span class="post-comments-count">
|
<a href="/2017/03/09/interviewTest/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/03/09/interviewTest/" itemprop="commentsCount"></span>
</a>
</span>
<span id="/2017/03/09/interviewTest/" class="leancloud_visitors" data-flag-title="使用vuejs开发的一个面试页面">
|
<span class="post-meta-item-icon">
<i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读次数 </span>
<span class="leancloud-visitors-count"></span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p><a href="https://github.com/fuliaoyi/showmecode" target="_blank" rel="external">试题链接</a></p>
<p><a href="https://github.com/yanghcc/interviewTest" target="_blank" rel="external">参考答案GitHub地址</a></p>
<p>演示效果:<br><img src="/images/operation1.gif" alt="pic"></p>
<h5 id="第一部分"><a href="#第一部分" class="headerlink" title="第一部分"></a>第一部分</h5><p>是关于javascript的简答题,考的是js基础知识。涉及的内容包括数组操作,js中改变this指向的方法call()以及js原型法。</p>
<h5 id="第二部分"><a href="#第二部分" class="headerlink" title="第二部分"></a>第二部分</h5><p>使用SPA框架开发一个滚动加载的页面,我使用的是vue.js,涉及的开发知识比较多。项目核心知识包括Vue.js,webpack,vue-scroller,axios,moment.js,xml2json.js,跨域问题,JavaScript正则匹配。数据源是<a href="http://36kr.com/feed" target="_blank" rel="external">http://36kr.com/feed</a>,数据格式是xml。</p>
<h4 id="正文如下。大家可以看看试题,再看看我的参考答案,以下是详细介绍,欢迎大家给参考答案点一个star"><a href="#正文如下。大家可以看看试题,再看看我的参考答案,以下是详细介绍,欢迎大家给参考答案点一个star" class="headerlink" title="正文如下。大家可以看看试题,再看看我的参考答案,以下是详细介绍,欢迎大家给参考答案点一个star~"></a>正文如下。大家可以看看试题,再看看我的参考答案,以下是详细介绍,欢迎大家给参考答案点一个star~</h4><p>1.项目结构直接使用vue-scroller的演示demo <a href="https://github.com/wangdahoo/vue-scroller-demo" target="_blank" rel="external">传送门</a></p>
<p>2.配置webpack,设置proxy代理,解决网络请求插件axios获取<a href="http://36kr.com/feed" target="_blank" rel="external">http://36kr.com/feed</a>存在跨域问题。在webpack.config.js中devServer的设置添加proxy,如下:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">devServer: {</div><div class="line"> historyApiFallback: true,</div><div class="line"> noInfo: true,</div><div class="line"> proxy: {</div><div class="line"> '/feed': {</div><div class="line"> target: 'http://36kr.com/',</div><div class="line"> changeOrigin: true,</div><div class="line"> secure: false</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>3.移动端使用相对长度单位rem,需要在index.html中添加一段js代码,根据屏幕尺寸设置根字体大小。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><script type=<span class="string">"text/javascript"</span>></div><div class="line"> <span class="built_in">window</span>.addEventListener(<span class="string">'resize'</span>, infinite);</div><div class="line"> <span class="function"><span class="keyword">function</span> <span class="title">infinite</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">const</span> html = <span class="built_in">document</span>.getElementsByTagName(<span class="string">'html'</span>)[<span class="number">0</span>];</div><div class="line"> <span class="keyword">const</span> htmlWidth = <span class="built_in">document</span>.body.clientWidth</div><div class="line"> <span class="keyword">if</span> (htmlWidth >= <span class="number">1080</span>) {</div><div class="line"> html.style.fontSize = <span class="string">"42px"</span>;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> html.style.fontSize = (<span class="number">42</span>/ <span class="number">1080</span> * htmlWidth) + <span class="string">'px'</span>;</div><div class="line"> }</div><div class="line"> }infinite();</div><div class="line"> </script></div></pre></td></tr></table></figure>
<p>4.这部分知识主要包括vue指令v-for、v-if、v-text、v-html。以及自定义事件refresh、infinite。css只要使用flex布局,比较简单不贴代码了,组件html结构如下:</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">template</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>></span></div><div class="line"> <span class="tag"><<span class="name">scroller</span> <span class="attr">:on-refresh</span>=<span class="string">"refresh"</span></span></div><div class="line"> <span class="attr">:on-infinite</span>=<span class="string">"infinite"</span></div><div class="line"> <span class="attr">ref</span>=<span class="string">"my_scroller"</span>></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">v-for</span>=<span class="string">"(item, index) in items"</span> <span class="attr">class</span>=<span class="string">"row"</span>></span></div><div class="line"> <span class="tag"><<span class="name">h1</span> <span class="attr">class</span>=<span class="string">"itme-title"</span> <span class="attr">v-text</span>=<span class="string">"item.title.__cdata"</span>></span><span class="tag"></<span class="name">h1</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"itembox"</span>></span></div><div class="line"> <span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"author"</span> <span class="attr">v-text</span>=<span class="string">"item.author"</span>></span><span class="tag"></<span class="name">span</span>></span></div><div class="line"> <span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"category"</span> <span class="attr">v-text</span>=<span class="string">"item.category"</span>></span><span class="tag"></<span class="name">span</span>></span></div><div class="line"> <span class="tag"><<span class="name">span</span> <span class="attr">class</span>=<span class="string">"timebox"</span> <span class="attr">v-text</span>=<span class="string">"newmoment(item.pubDate.__cdata)"</span>></span><span class="tag"></<span class="name">span</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">a</span> <span class="attr">class</span>=<span class="string">"item-content"</span> <span class="attr">:href</span>=<span class="string">"item.link"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"leftbox"</span> <span class="attr">v-html</span>=<span class="string">"handlerData(item.description.__cdata)"</span>></span><span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"rightbox"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"imgbox"</span>></span></div><div class="line"> <span class="tag"><<span class="name">img</span> <span class="attr">class</span>=<span class="string">"img"</span> <span class="attr">:src</span>=<span class="string">"skewImg.url?skewImg.url:'/src/assets/404.jpg'"</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">a</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">scroller</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"><span class="tag"></<span class="name">template</span>></span></div></pre></td></tr></table></figure>
<p>5.在vue生命周期created阶段,通过axios发起网络请求,获取数据之后,将数据经过xml2json插件转换后,保存json数据到本地数组。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"> data() {</div><div class="line"> <span class="keyword">return</span> {</div><div class="line"> <span class="attr">items</span>: [],<span class="comment">//当前渲染数据</span></div><div class="line"> allData: [],<span class="comment">//所有数据</span></div><div class="line"> dataLen: <span class="number">0</span>,<span class="comment">//数据总长度</span></div><div class="line"> step: <span class="number">10</span>,<span class="comment">//上拉加载时,每次载入数据的数量</span></div><div class="line"> times: <span class="number">0</span>,<span class="comment">//上拉加载次数</span></div><div class="line"> skewImg: []<span class="comment">//缩略图保存地址</span></div><div class="line"> }</div><div class="line"> },</div><div class="line">created() {</div><div class="line"> <span class="keyword">var</span> dataObj = {};</div><div class="line"> <span class="keyword">var</span> self = <span class="keyword">this</span>;</div><div class="line"> axios.get(<span class="string">'/feed'</span>)</div><div class="line"> .then(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>{</div><div class="line"> <span class="keyword">var</span> x2js = <span class="keyword">new</span> X2JS();</div><div class="line"> <span class="keyword">var</span> dataObj = response.data;</div><div class="line"> <span class="keyword">var</span> jsonObj = x2js.xml_str2json( dataObj );</div><div class="line"> <span class="keyword">var</span> itemData = jsonObj.rss.channel.item;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = itemData.length; i >= <span class="number">0</span>; i--) {</div><div class="line"> self.allData.push(itemData[i])</div><div class="line"> }</div><div class="line"> self.dataLen = self.allData.length;</div><div class="line"> })</div><div class="line"> .catch(<span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(error);</div><div class="line"> });</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>6.渲染到页面前数据处理,若当前item有多张图片,则保存第一张图片的src地址,若没有图片则保存一个空值。然后将数据去除所有html标签,只保留300个字符长度的文本,渲染到页面中:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">handlerData(str) {</div><div class="line"> <span class="keyword">var</span> self = <span class="keyword">this</span>;</div><div class="line"> <span class="keyword">var</span> dd = <span class="string">''</span>;</div><div class="line"> <span class="keyword">var</span> arr = str.replace(<span class="regexp">/<img [^>]*src=['"]([^'"]+)[^>]*>/i</span>, <span class="function"><span class="keyword">function</span> (<span class="params">match, capture</span>) </span>{</div><div class="line"> dd = capture</div><div class="line"> });</div><div class="line"> self.skewImg[<span class="string">'url'</span>] = dd;</div><div class="line"></div><div class="line"> <span class="keyword">var</span> str = str.substring(<span class="number">0</span>,<span class="number">300</span>);</div><div class="line"> <span class="keyword">return</span> str.replace(<span class="regexp">/<[^>]+>/g</span>,<span class="string">""</span>);</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>7.渲染到页面前,使用moment.js格式化时间。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">newmoment(arg) {</div><div class="line"> <span class="keyword">return</span> moment(arg).format(<span class="string">'MM 月 DD 日 hh:mm'</span>)</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>8.上拉加载更多调用infinite()方法,每次上拉操作,次数times自加1,并往items数组添加step长度的数据:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">infinite() {</div><div class="line"> <span class="keyword">var</span> self = <span class="keyword">this</span>;</div><div class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</div><div class="line"> self.times +=<span class="number">1</span>;</div><div class="line"> <span class="keyword">var</span> end = ((self.step)+<span class="number">1</span>)*self.times;</div><div class="line"> <span class="keyword">var</span> sta = end - self.step;</div><div class="line"> self.items = self.items.concat(self.allData.slice(sta,end));</div><div class="line"> <span class="comment">// console.log(self.items.length)</span></div><div class="line"> <span class="keyword">if</span> (self.items.length >= self.allData) {</div><div class="line"> <span class="keyword">this</span>.$refs.my_scroller.finishInfinite(<span class="literal">true</span>)</div><div class="line"> }</div><div class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</div><div class="line"> <span class="keyword">this</span>.$refs.my_scroller.finishInfinite(<span class="literal">true</span>)</div><div class="line"> })</div><div class="line"> }, <span class="number">1500</span>)</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>9.下拉刷新调用reflesh()方法,重新发起一次网络请求,并且往items中填充step条数据:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line">refresh() {</div><div class="line"> setTimeout(<span class="function"><span class="params">()</span> =></span> {</div><div class="line"> <span class="keyword">var</span> dataObj = {};</div><div class="line"> <span class="keyword">var</span> self = <span class="keyword">this</span>;</div><div class="line"> axios.get(<span class="string">'/feed'</span>)</div><div class="line"> .then(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>{</div><div class="line"> <span class="keyword">var</span> x2js = <span class="keyword">new</span> X2JS();</div><div class="line"> <span class="keyword">var</span> dataObj = response.data;</div><div class="line"> <span class="keyword">var</span> jsonObj = x2js.xml_str2json( dataObj );</div><div class="line"> <span class="keyword">var</span> itemData = jsonObj.rss.channel.item;</div><div class="line"> self.items = [];<span class="comment">//重置数据</span></div><div class="line"> self.allData = [];<span class="comment">//重置数据</span></div><div class="line"> self.times = <span class="number">1</span>;<span class="comment">//重置数据</span></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">var</span> i = itemData.length; i >= <span class="number">0</span>; i--) {</div><div class="line"> self.allData.push(itemData[i])</div><div class="line"> }</div><div class="line"> self.allData.shift();<span class="comment">//删除数组第一个数据</span></div><div class="line"> <span class="keyword">var</span> end = ((self.step)+<span class="number">1</span>)*self.times;</div><div class="line"> <span class="keyword">var</span> sta = end - self.step;</div><div class="line"> self.items = self.allData.slice(sta,end);</div><div class="line"> })</div><div class="line"> .catch(<span class="function"><span class="keyword">function</span> (<span class="params">error</span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(error);</div><div class="line"> });</div><div class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.$refs.my_scroller)</div><div class="line"> <span class="keyword">this</span>.$refs.my_scroller.finishPullToRefresh();</div><div class="line"> }, <span class="number">1500</span>)</div><div class="line"> }</div></pre></td></tr></table></figure>
<p>最后是遗留问题:应该是webpack配置有点问题,执行build打包之后,设置的proxy代理失效。求大神帮忙看看。</p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/03/06/javascript_optimization/" itemprop="url">
如何优化javascript代码提高性能
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2017-03-06T11:30:28+08:00" content="2017-03-06">
2017-03-06
</time>
</span>
<span class="post-category" >
|
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="https://schema.org/Thing">
<a href="/categories/javaScript/" itemprop="url" rel="index">
<span itemprop="name">javaScript</span>
</a>
</span>
</span>
<span class="post-comments-count">
|
<a href="/2017/03/06/javascript_optimization/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/03/06/javascript_optimization/" itemprop="commentsCount"></span>
</a>
</span>
<span id="/2017/03/06/javascript_optimization/" class="leancloud_visitors" data-flag-title="如何优化javascript代码提高性能">
|
<span class="post-meta-item-icon">
<i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读次数 </span>
<span class="leancloud-visitors-count"></span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="一.Javascript代码执行效率"><a href="#一.Javascript代码执行效率" class="headerlink" title="一.Javascript代码执行效率"></a>一.Javascript代码执行效率</h3><h4 id="1-DOM操作"><a href="#1-DOM操作" class="headerlink" title="1. DOM操作"></a>1. DOM操作</h4><p>1.1 使用 DocumentFragment 优化多次 append<br>说明:添加多个 dom 元素时,先将元素 append 到 DocumentFragment 中,最后统一将 DocumentFragment 添加到页面。</p>
<p>该做法可以减少页面渲染 dom 元素的次数。经 IE 和 Fx 下测试,在 append1000 个元素时,效率能提高 10%-30% , Fx 下提升较为明显。<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> (var i = 0; i < 1000; i++) {</div><div class="line"> var el = document.createElement(<span class="string">'p'</span>);</div><div class="line"> el.innerHTML = i;</div><div class="line"> document.body.appendChild(el);</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">var frag = document.createDocumentFragment();</div><div class="line"><span class="keyword">for</span> (var i = 0; i < 1000; i++) {</div><div class="line"> var el = document.createElement(<span class="string">'p'</span>);</div><div class="line"> el.innerHTML = i;</div><div class="line"> frag.appendChild(el);</div><div class="line">}</div><div class="line">document.body.appendChild(frag);</div></pre></td></tr></table></figure></p>
<p>1.2 通过模板元素 clone ,替代 createElement</p>
<p>说明:通过一个模板 dom 对象 cloneNode ,效率比直接创建 element 高。性能提高不明显,约为 10% 左右。在低于 100 个元素 create 和 append 操作时,没有优势。<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">var frag = document.createDocumentFragment();</div><div class="line"><span class="keyword">for</span> (var i = 0; i < 1000; i++) {</div><div class="line"> var el = document.createElement(<span class="string">'p'</span>);</div><div class="line"> el.innerHTML = i;</div><div class="line"> frag.appendChild(el);</div><div class="line">}</div><div class="line">document.body.appendChild(frag);</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">var frag = document.createDocumentFragment();</div><div class="line">var pEl = document.getElementsByTagName(<span class="string">'p'</span>)[0];</div><div class="line"><span class="keyword">for</span> (var i = 0; i < 1000; i++) {</div><div class="line"> var el = pEl.cloneNode(<span class="literal">false</span>);</div><div class="line"> el.innerHTML = i;</div><div class="line"> frag.appendChild(el);</div><div class="line">}</div><div class="line">document.body.appendChild(frag);</div></pre></td></tr></table></figure></p>
<p>1.3 使用一次 innerHTML 赋值代替构建 dom 元素</p>
<p>说明:根据数据构建列表样式的时候,使用设置列表容器 innerHTML 的方式,比构建 dom 元素并 append 到页面中的方式,效率有数量级上的提高。</p>
<p>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">var frag = document.createDocumentFragment();</div><div class="line"><span class="keyword">for</span> (var i = 0; i < 1000; i++) {</div><div class="line"> var el = document.createElement(<span class="string">'p'</span>);</div><div class="line"> el.innerHTML = i;</div><div class="line"> frag.appendChild(el);</div><div class="line">}</div><div class="line">document.body.appendChild(frag);</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">var html = [];</div><div class="line"><span class="keyword">for</span> (var i = 0; i < 1000; i++) {</div><div class="line"> html.push(<span class="string">'</span></div><div class="line">' + i + <span class="string">'</span></div><div class="line">');</div><div class="line">}</div><div class="line">document.body.innerHTML = html.join(<span class="string">''</span>);</div></pre></td></tr></table></figure></p>
<p>1.4 使用 firstChild 和 nextSibling 代替 childNodes 遍历 dom 元素<br>说明:约能获得 30%-50% 的性能提高。逆向遍历时使用 lastChild 和 previousSibling 。<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">var nodes = element.childNodes;</div><div class="line"><span class="keyword">for</span> (var i = 0, l = nodes.length; i < l; i++) {</div><div class="line">var node = nodes[i];</div><div class="line">……</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">var node = element.firstChild;</div><div class="line"><span class="keyword">while</span> (node) {</div><div class="line">……</div><div class="line">nodenode = node.nextSibling;</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h4 id="2-字符串"><a href="#2-字符串" class="headerlink" title="2. 字符串"></a>2. 字符串</h4><p>2.1 使用 Array 做为 StringBuffer ,代替字符串拼接的操作<br>说明: IE 在对字符串拼接的时候,会创建临时的 String 对象;经测试,在 IE 下,当拼接的字符串越来越大时,运行效率会急剧下降。 Fx 和 Opera 都 对字符串拼接操作进行了优化;经测试,在 Fx 下,使用 Array 的 join 方式执行时间约为直接字符串拼接的 1.4 倍。<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">var now = new Date();</div><div class="line">var str = <span class="string">''</span>;</div><div class="line"><span class="keyword">for</span> (var i = 0; i < 10000; i++) {</div><div class="line"> str += <span class="string">'123456789123456789'</span>;</div><div class="line">}</div><div class="line">alert(new Date() - now);</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">var now = new Date();</div><div class="line">var strBuffer = [];</div><div class="line"><span class="keyword">for</span> (var i = 0; i < 10000; i++) {</div><div class="line"> strBuffer.push(<span class="string">'123456789123456789'</span>);</div><div class="line">}</div><div class="line">var str = strBuffer.join(<span class="string">''</span>);</div><div class="line">alert(new Date() - now);</div></pre></td></tr></table></figure></p>
<h4 id="3-循环语句"><a href="#3-循环语句" class="headerlink" title="3. 循环语句"></a>3. 循环语句</h4><p>3.1 将循环控制量保存到局部变量<br>说明:对数组和列表对象的遍历时,提前将 length 保存到局部变量中,避免在循环的每一步重复取值。<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">var list = document.getElementsByTagName(<span class="string">'p'</span>);</div><div class="line"><span class="keyword">for</span> (var i = 0; i < list.length; i++) {</div><div class="line"> ……</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">var list = document.getElementsByTagName(<span class="string">'p'</span>);</div><div class="line"><span class="keyword">for</span> (var i = 0, l = list.length; i < l; i++) {</div><div class="line"> ……</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>3.2 顺序无关的遍历时,用 while 替代 for<br>说明:该方法可以减少局部变量的使用。比起效率优化,更能直接看到的是字符数量的优化。该做法有程序员强迫症的嫌疑。<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">var arr = [1,2,3,4,5,6,7];</div><div class="line">var sum = 0;</div><div class="line"><span class="keyword">for</span> (var i = 0, l = arr.length; i < l; i++) {</div><div class="line"> sum += arr[i];</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">var arr = [1,2,3,4,5,6,7];</div><div class="line">var sum = 0, l = arr.length;</div><div class="line"><span class="keyword">while</span> (l--) {</div><div class="line"> sum += arr[l];</div><div class="line">}</div></pre></td></tr></table></figure></p>
<h4 id="4-条件分支"><a href="#4-条件分支" class="headerlink" title="4. 条件分支"></a>4. 条件分支</h4><p>4.1 将条件分支,按可能性顺序从高到低排列<br>说明:可以减少解释器对条件的探测次数。</p>
<p>4.2 在同一条件子的多( >2 )条件分支时,使用 switch 优于 if<br>说明: switch 分支选择的效率高于 if ,在 IE 下尤为明显。 4 分支的测试, IE 下 switch 的执行时间约为 if 的一半。</p>
<p>4.3 使用三目运算符替代条件分支<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (a > b) {</div><div class="line">num = a;</div><div class="line">} <span class="keyword">else</span> {</div><div class="line">num = b;</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">num = a > b ? a : b;</div></pre></td></tr></table></figure></p>
<h4 id="5-定时器"><a href="#5-定时器" class="headerlink" title="5. 定时器"></a>5. 定时器</h4><p>5.1 需要不断执行的时候,优先考虑使用 setInterval<br>说明: setTimeout 每一次都会初始化一个定时器。 setInterval 只会在开始的时候初始化一个定时器<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">var timeoutTimes = 0;</div><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">timeout</span></span> () {</div><div class="line"> timeoutTimes++;</div><div class="line"> <span class="keyword">if</span> (timeoutTimes < 10) {</div><div class="line"> <span class="built_in">set</span>Timeout(timeout, 10);</div><div class="line"> }</div><div class="line">}</div><div class="line">timeout();</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">var intervalTimes = 0;</div><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">interval</span></span> () {</div><div class="line"> intervalTimes++;</div><div class="line"> <span class="keyword">if</span> (intervalTimes >= 10) {</div><div class="line"> clearInterval(interv);</div><div class="line"> }</div><div class="line">}</div><div class="line">var interv = <span class="built_in">set</span>Interval(interval, 10);</div></pre></td></tr></table></figure></p>
<p>5.2 使用 function 而不是 string<br>说明:如果把字符串作为 setTimeout 和 setInterval 的参数,浏览器会先用这个字符串构建一个 function 。</p>
<p>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">var num = 0;</div><div class="line"><span class="built_in">set</span>Timeout(<span class="string">'num++'</span>, 10);</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">var num = 0;</div><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">addNum</span></span> () {</div><div class="line"> num++;</div><div class="line">}</div><div class="line"><span class="built_in">set</span>Timeout(addNum, 10);</div></pre></td></tr></table></figure></p>
<h4 id="6-其他"><a href="#6-其他" class="headerlink" title="6. 其他"></a>6. 其他</h4><p>6.1 尽量不使用动态语法元素</p>
<p>说明: eval 、 Function 、 execScript 等语句会再次使用 javascript 解析引擎进行解析,需要消耗大量的执行时间。</p>
<p>6.2 重复使用的调用结果,事先保存到局部变量</p>
<p>说明:避免多次取值的调用开销。<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">var h1 = element1.clientHeight + num1;</div><div class="line">var h2 = element1.clientHeight + num2;</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">var eleHeight = element1.clientHeight;</div><div class="line">var h1 = eleHeight + num1;</div><div class="line">var h2 = eleHeight + num2;</div></pre></td></tr></table></figure></p>
<p>6.3 使用直接量<br>说明:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">var a = new Array(param,param,...) -> var a = []</div><div class="line">var foo = new Object() -> var foo = {}</div><div class="line">var reg = new RegExp() -> var reg = /.../</div></pre></td></tr></table></figure></p>
<p>6.4 避免使用 with</p>
<p>说明: with 虽然可以缩短代码量,但是会在运行时构造一个新的 scope 。<br>OperaDev 上还有这样的解释,使用 with 语句会使得解释器无法在语法解析阶段对代码进行优化。对此说法,无法验证。<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">with (a.b.c.d) {</div><div class="line">property1 = 1;</div><div class="line">property2 = 2;</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">var obj = a.b.c.d;</div><div class="line">obj.property1 = 1;</div><div class="line">obj.property2 = 2;</div></pre></td></tr></table></figure></p>
<p>6.5 巧用 || 和 && 布尔运算符<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> eventHandler (e) {</div><div class="line"><span class="keyword">if</span>(!e) e = window.event;</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> eventHandler (e) {</div><div class="line">ee = e || window.event;</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (myobj) {</div><div class="line"><span class="keyword">do</span>Something(myobj);</div><div class="line">}</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">myobj && <span class="keyword">do</span>Something(myobj);</div></pre></td></tr></table></figure></p>
<p>6.6 类型转换</p>
<p>说明:</p>
<p>1). 数字转换成字符串,应用 “” + 1 ,性能上: (“” +) > String() > .toString() > new String() ;</p>
<p>2). 浮点数转换成整型,不使用 parseInt() , parseInt() 是用于将字符串转换成数字,而不是浮点数和整型之间的转换,建议使用 Math.floor() 或者 Math.round()</p>
<p>3). 对于自定义的对象,推荐显式调用 toString() 。内部操作在尝试所有可能性之后,会尝试对象的 toString() 方法尝试能否转化为 String 。</p>
<h3 id="二.内存管理"><a href="#二.内存管理" class="headerlink" title="二.内存管理"></a>二.内存管理</h3><h4 id="2-1-循环引用"><a href="#2-1-循环引用" class="headerlink" title="2.1 循环引用"></a>2.1 循环引用</h4><p>说明:如果循环引用中包含 DOM 对象或者 ActiveX 对象,那么就会发生内存泄露。内存泄露的后果是在浏览器关闭前,即使是刷新页面,这部分内存不会被浏览器释放。</p>
<p>简单的循环引用:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">var el = document.getElementById(<span class="string">'MyElement'</span>);</div><div class="line">var func = <span class="function"><span class="title">function</span></span> () {…}</div><div class="line">el.func = func;</div><div class="line">func.element = el;</div></pre></td></tr></table></figure></p>
<p>但是通常不会出现这种情况。通常循环引用发生在为 dom 元素添加闭包作为 expendo 的时候。</p>
<p>如:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">init</span></span>() {</div><div class="line"> var el = document.getElementById(<span class="string">'MyElement'</span>);</div><div class="line">el.onclick = <span class="function"><span class="title">function</span></span> () {……}</div><div class="line">}</div><div class="line">init();</div></pre></td></tr></table></figure></p>
<p>init 在执行的时候,当前上下文我们叫做 context 。这个时候, context 引用了 el , el 引用了 function , function 引用了 context 。这时候形成了一个循环引用。</p>
<p>下面 2 种方法可以解决循环引用:</p>
<p>1) 置空 dom 对象<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">init</span></span>() {</div><div class="line">var el = document.getElementById(<span class="string">'MyElement'</span>);</div><div class="line">el.onclick = <span class="function"><span class="title">function</span></span> () {……}</div><div class="line">}</div><div class="line">init();</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">init</span></span>() {</div><div class="line">var el = document.getElementById(<span class="string">'MyElement'</span>);</div><div class="line">el.onclick = <span class="function"><span class="title">function</span></span> () {……}</div><div class="line">el = null;</div><div class="line">}</div><div class="line">init();</div></pre></td></tr></table></figure></p>
<p>将 el 置空, context 中不包含对 dom 对象的引用,从而打断循环应用。<br>如果我们需要将 dom 对象返回,可以用如下方法:<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">init</span></span>() {</div><div class="line"> var el = document.getElementById(<span class="string">'MyElement'</span>);</div><div class="line"> el.onclick = <span class="function"><span class="title">function</span></span> () {……}</div><div class="line"> <span class="built_in">return</span> el;</div><div class="line">}</div><div class="line">init();</div></pre></td></tr></table></figure></p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line">优化后:</div><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">init</span></span>() {</div><div class="line">var el = document.getElementById(<span class="string">'MyElement'</span>);</div><div class="line">el.onclick = <span class="function"><span class="title">function</span></span> () {……}</div><div class="line">try{</div><div class="line"><span class="built_in">return</span> el;</div><div class="line">} finally {</div><div class="line"> el = null;</div><div class="line">}</div><div class="line">}</div><div class="line">init();</div></pre></td></tr></table></figure>
<p>2) 构造新的 context<br>优化前:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">init</span></span>() {</div><div class="line"> var el = document.getElementById(<span class="string">'MyElement'</span>);</div><div class="line"> el.onclick = <span class="function"><span class="title">function</span></span> () {……}</div><div class="line">}</div><div class="line">init();</div></pre></td></tr></table></figure></p>
<p>优化后:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">elClickHandler</span></span>() {……}</div><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">init</span></span>() {</div><div class="line"> var el = document.getElementById(<span class="string">'MyElement'</span>);</div><div class="line"> el.onclick = elClickHandler;</div><div class="line">}</div><div class="line">init();</div></pre></td></tr></table></figure></p>
<p>把 function 抽到新的 context 中,这样, function 的 context 就不包含对 el 的引用,从而打断循环引用。</p>
<h4 id="2-2-通过-javascript-创建的-dom-对象,必须-append-到页面中"><a href="#2-2-通过-javascript-创建的-dom-对象,必须-append-到页面中" class="headerlink" title="2.2 通过 javascript 创建的 dom 对象,必须 append 到页面中"></a>2.2 通过 javascript 创建的 dom 对象,必须 append 到页面中</h4><p>说明: IE 下,脚本创建的 dom 对象,如果没有 append 到页面中,刷新页面,这部分内存是不会回收的!<br>示例代码:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">function</span> <span class="function"><span class="title">create</span></span> () {</div><div class="line"> var gc = document.getElementById(<span class="string">'GC'</span>);</div><div class="line"> <span class="keyword">for</span> (var i = 0; i < 5000 ; i++)</div><div class="line"> {</div><div class="line"> var el = document.createElement(<span class="string">'div'</span>);</div><div class="line"> el.innerHTML = <span class="string">"test"</span>;</div><div class="line"></div><div class="line"> // 下面这句可以注释掉,看看浏览器在任务管理器中,点击按钮然后刷新后的内存变化</div><div class="line"> gc.appendChild(el);</div><div class="line"> }</div><div class="line"> }</div></pre></td></tr></table></figure></p>
<h4 id="2-3-释放-dom-元素占用的内存"><a href="#2-3-释放-dom-元素占用的内存" class="headerlink" title="2.3 释放 dom 元素占用的内存"></a>2.3 释放 dom 元素占用的内存</h4><p>说明:<br>将 dom 元素的 innerHTML 设置为空字符串,可以释放其子元素占用的内存。<br>在 rich 应用中,用户也许会在一个页面上停留很长时间,可以使用该方法释放积累得越来越多的 dom 元素使用的内存。</p>
<h4 id="2-4-释放-javascript-对象"><a href="#2-4-释放-javascript-对象" class="headerlink" title="2.4 释放 javascript 对象"></a>2.4 释放 javascript 对象</h4><p>说明:在 rich 应用中,随着实例化对象数量的增加,内存消耗会越来越大。所以应当及时释放对对象的引用,让 GC 能够回收这些内存控件。<br>对象: obj = null<br>对象属性: delete obj.myproperty<br>数组 item :使用数组的 splice 方法释放数组中不用的 item</p>
<h4 id="2-5-避免-string-的隐式装箱"><a href="#2-5-避免-string-的隐式装箱" class="headerlink" title="2.5 避免 string 的隐式装箱"></a>2.5 避免 string 的隐式装箱</h4><p>说明:对 string 的方法调用,比如 ‘xxx’.length ,浏览器会进行一个隐式的装箱操作,将字符串先转换成一个 String 对象。推荐对声明有可能使用 String 实例方法的字符串时,采用如下写法:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">var myString = new String(<span class="string">'Hello World'</span>);</div></pre></td></tr></table></figure></p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/02/25/javascript_closure/" itemprop="url">
javascript闭包
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2017-02-25T20:39:47+08:00" content="2017-02-25">
2017-02-25
</time>
</span>
<span class="post-category" >
|
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="https://schema.org/Thing">
<a href="/categories/javaScript/" itemprop="url" rel="index">
<span itemprop="name">javaScript</span>
</a>
</span>
</span>
<span class="post-comments-count">
|
<a href="/2017/02/25/javascript_closure/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/02/25/javascript_closure/" itemprop="commentsCount"></span>
</a>
</span>
<span id="/2017/02/25/javascript_closure/" class="leancloud_visitors" data-flag-title="javascript闭包">
|
<span class="post-meta-item-icon">
<i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读次数 </span>
<span class="leancloud-visitors-count"></span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h3 id="学习Javascript闭包(Closure)"><a href="#学习Javascript闭包(Closure)" class="headerlink" title="学习Javascript闭包(Closure)"></a>学习Javascript闭包(Closure)</h3><p>闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。<br>下面就是我的学习笔记,对于Javascript初学者应该是很有用的。</p>
<h4 id="一、变量的作用域"><a href="#一、变量的作用域" class="headerlink" title="一、变量的作用域"></a>一、变量的作用域</h4><p>要理解闭包,首先必须理解Javascript特殊的变量作用域。<br>变量的作用域无非就是两种:全局变量和局部变量。<br>Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"> var n=999;</div><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f1</span></span>(){</div><div class="line"> alert(n);</div><div class="line"> }</div><div class="line"> f1(); // 999</div></pre></td></tr></table></figure></p>
<p>另一方面,在函数外部自然无法读取函数内的局部变量。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f1</span></span>(){</div><div class="line"> var n=999;</div><div class="line"> }</div><div class="line"> alert(n); // error</div></pre></td></tr></table></figure></p>
<p>这里有一个地方需要注意,函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明了一个全局变量!<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f1</span></span>(){</div><div class="line"> n=999;</div><div class="line"> }</div><div class="line"> f1();</div><div class="line"> alert(n); // 999</div></pre></td></tr></table></figure></p>
<h4 id="二、如何从外部读取局部变量?"><a href="#二、如何从外部读取局部变量?" class="headerlink" title="二、如何从外部读取局部变量?"></a>二、如何从外部读取局部变量?</h4><p>出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。<br>那就是在函数的内部,再定义一个函数。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f1</span></span>(){</div><div class="line"> var n=999;</div><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f2</span></span>(){</div><div class="line"> alert(n); // 999</div><div class="line"> }</div><div class="line"> }</div></pre></td></tr></table></figure></p>
<p>在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是Javascript语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。<br>既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f1</span></span>(){</div><div class="line"> var n=999;</div><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f2</span></span>(){</div><div class="line"> alert(n); </div><div class="line"> }</div><div class="line"> <span class="built_in">return</span> f2;</div><div class="line"> }</div><div class="line"> var result=f1();</div><div class="line"> result(); // 999</div></pre></td></tr></table></figure></p>
<h4 id="三、闭包的概念"><a href="#三、闭包的概念" class="headerlink" title="三、闭包的概念"></a>三、闭包的概念</h4><p>上一节代码中的f2函数,就是闭包。<br>各种专业文献上的”闭包”(closure)定义非常抽象,很难看懂。我的理解是,闭包就是能够读取其他函数内部变量的函数。<br>由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。<br>所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。</p>
<h4 id="四、闭包的用途"><a href="#四、闭包的用途" class="headerlink" title="四、闭包的用途"></a>四、闭包的用途</h4><p>闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。<br>怎么来理解这句话呢?请看下面的代码。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f1</span></span>(){</div><div class="line"> var n=999;</div><div class="line"> nAdd=<span class="function"><span class="title">function</span></span>(){n+=1}</div><div class="line"> <span class="keyword">function</span> <span class="function"><span class="title">f2</span></span>(){</div><div class="line"> alert(n);</div><div class="line"> }</div><div class="line"> <span class="built_in">return</span> f2;</div><div class="line"> }</div><div class="line"> var result=f1();</div><div class="line"> result(); // 999</div><div class="line"> nAdd();</div><div class="line"> result(); // 1000</div></pre></td></tr></table></figure></p>
<p>在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。<br>为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。<br>这段代码中另一个值得注意的地方,就是”nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。</p>
<h4 id="五、使用闭包的注意点"><a href="#五、使用闭包的注意点" class="headerlink" title="五、使用闭包的注意点"></a>五、使用闭包的注意点</h4><p>1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。<br>2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。</p>
<h4 id="六、思考题"><a href="#六、思考题" class="headerlink" title="六、思考题"></a>六、思考题</h4><p>如果你能理解下面两段代码的运行结果,应该就算理解闭包的运行机制了。<br>代码片段一。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"> var name = <span class="string">"The Window"</span>;</div><div class="line"> var object = {</div><div class="line"> name : <span class="string">"My Object"</span>,</div><div class="line"> getNameFunc : <span class="function"><span class="title">function</span></span>(){</div><div class="line"> <span class="built_in">return</span> <span class="function"><span class="title">function</span></span>(){</div><div class="line"> <span class="built_in">return</span> this.name;</div><div class="line"> };</div><div class="line"> }</div><div class="line"> };</div><div class="line"> alert(object.getNameFunc()());</div></pre></td></tr></table></figure></p>
<p>代码片段二。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"> var name = <span class="string">"The Window"</span>;</div><div class="line"> var object = {</div><div class="line"> name : <span class="string">"My Object"</span>,</div><div class="line"> getNameFunc : <span class="function"><span class="title">function</span></span>(){</div><div class="line"> var that = this;</div><div class="line"> <span class="built_in">return</span> <span class="function"><span class="title">function</span></span>(){</div><div class="line"> <span class="built_in">return</span> that.name;</div><div class="line"> };</div><div class="line"> }</div><div class="line"> };</div><div class="line"> alert(object.getNameFunc()());</div></pre></td></tr></table></figure></p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/02/24/http_protocol_entry/" itemprop="url">
http_agreement
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2017-02-24T16:59:21+08:00" content="2017-02-24">
2017-02-24
</time>
</span>
<span class="post-category" >
|
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="https://schema.org/Thing">
<a href="/categories/others/" itemprop="url" rel="index">
<span itemprop="name">others</span>
</a>
</span>
</span>
<span class="post-comments-count">
|
<a href="/2017/02/24/http_protocol_entry/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/02/24/http_protocol_entry/" itemprop="commentsCount"></span>
</a>
</span>
<span id="/2017/02/24/http_protocol_entry/" class="leancloud_visitors" data-flag-title="http_agreement">
|
<span class="post-meta-item-icon">
<i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读次数 </span>
<span class="leancloud-visitors-count"></span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="HTTP-协议入门"><a href="#HTTP-协议入门" class="headerlink" title="HTTP 协议入门"></a>HTTP 协议入门</h2><p>作者: 阮一峰 <a href="http://www.ruanyifeng.com/blog/2016/08/http.html" target="_blank" rel="external">转载地址</a><br>HTTP 协议是互联网的基础协议,也是网页开发的必备知识,最新版本 HTTP/2 更是让它成为技术热点。<br>本文介绍 HTTP 协议的历史演变和设计思路。</p>
<h3 id="一、HTTP-0-9"><a href="#一、HTTP-0-9" class="headerlink" title="一、HTTP/0.9"></a>一、HTTP/0.9</h3><p>HTTP 是基于 TCP/IP 协议的应用层协议。它不涉及数据包(packet)传输,主要规定了客户端和服务器之间的通信格式,默认使用80端口。<br>最早版本是1991年发布的0.9版。该版本极其简单,只有一个命令GET。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">GET /index.html</div></pre></td></tr></table></figure></p>
<p>上面命令表示,TCP 连接(connection)建立后,客户端向服务器请求(request)网页index.html。<br>协议规定,服务器只能回应HTML格式的字符串,不能回应别的格式。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><html></div><div class="line"> <body>Hello World</body></div><div class="line"></html></div></pre></td></tr></table></figure></p>
<p>服务器发送完毕,就关闭TCP连接。</p>
<h3 id="二、HTTP-1-0"><a href="#二、HTTP-1-0" class="headerlink" title="二、HTTP/1.0"></a>二、HTTP/1.0</h3><p>2.1 简介<br>1996年5月,HTTP/1.0 版本发布,内容大大增加。<br>首先,任何格式的内容都可以发送。这使得互联网不仅可以传输文字,还能传输图像、视频、二进制文件。这为互联网的大发展奠定了基础。<br>其次,除了GET命令,还引入了POST命令和HEAD命令,丰富了浏览器与服务器的互动手段。<br>再次,HTTP请求和回应的格式也变了。除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。<br>其他的新增功能还包括状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。<br>2.2 请求格式<br>下面是一个1.0版的HTTP请求的例子。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">GET / HTTP/1.0</div><div class="line">User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)</div><div class="line">Accept: */*</div></pre></td></tr></table></figure></p>
<p>可以看到,这个格式与0.9版有很大变化。<br>第一行是请求命令,必须在尾部添加协议版本(HTTP/1.0)。后面就是多行头信息,描述客户端的情况。<br>2.3 回应格式<br>服务器的回应如下。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">HTTP/1.0 200 OK</div><div class="line">Content-Type: text/plain</div><div class="line">Content-Length: 137582</div><div class="line">Expires: Thu, 05 Dec 1997 16:00:00 GMT</div><div class="line">Last-Modified: Wed, 5 August 1996 15:55:28 GMT</div><div class="line">Server: Apache 0.84</div><div class="line"></div><div class="line"><html></div><div class="line"> <body>Hello World</body></div><div class="line"></html></div></pre></td></tr></table></figure></p>
<p>回应的格式是”头信息 + 一个空行(\r\n) + 数据”。其中,第一行是”协议版本 + 状态码(status code) + 状态描述”。<br>2.4 Content-Type 字段<br>关于字符的编码,1.0版规定,头信息必须是 ASCII 码,后面的数据可以是任何格式。因此,服务器回应的时候,必须告诉客户端,数据是什么格式,这就是Content-Type字段的作用。<br>下面是一些常见的Content-Type字段的值。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">text/plain</div><div class="line">text/html</div><div class="line">text/css</div><div class="line">image/jpeg</div><div class="line">image/png</div><div class="line">image/svg+xml</div><div class="line">audio/mp4</div><div class="line">video/mp4</div><div class="line">application/javascript</div><div class="line">application/pdf</div><div class="line">application/zip</div><div class="line">application/atom+xml</div></pre></td></tr></table></figure></p>
<p>这些数据类型总称为MIME type,每个值包括一级类型和二级类型,之间用斜杠分隔。<br>除了预定义的类型,厂商也可以自定义类型。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">application/vnd.debian.binary-package</div></pre></td></tr></table></figure></p>
<p>上面的类型表明,发送的是Debian系统的二进制数据包。<br>MIME type还可以在尾部使用分号,添加参数。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Content-Type: text/html; charset=utf-8</div></pre></td></tr></table></figure></p>
<p>上面的类型表明,发送的是网页,而且编码是UTF-8。<br>客户端请求的时候,可以使用Accept字段声明自己可以接受哪些数据格式。</p>
<p>Accept: <em>/</em><br>上面代码中,客户端声明自己可以接受任何格式的数据。<br>MIME type不仅用在HTTP协议,还可以用在其他地方,比如HTML网页。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><meta http-equiv=<span class="string">"Content-Type"</span> content=<span class="string">"text/html; charset=UTF-8"</span> /></div><div class="line"><!-- 等同于 --></div><div class="line"><meta charset=<span class="string">"utf-8"</span> /></div></pre></td></tr></table></figure></p>
<p>2.5 Content-Encoding 字段<br>由于发送的数据可以是任何格式,因此可以把数据压缩后再发送。Content-Encoding字段说明数据的压缩方法。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">Content-Encoding: gzip</div><div class="line">Content-Encoding: compress</div><div class="line">Content-Encoding: deflate</div></pre></td></tr></table></figure></p>
<p>客户端在请求时,用Accept-Encoding字段说明自己可以接受哪些压缩方法。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Accept-Encoding: gzip, deflate</div></pre></td></tr></table></figure></p>
<p>2.6 缺点<br>HTTP/1.0 版的主要缺点是,每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。<br>TCP连接的新建成本很高,因为需要客户端和服务器三次握手,并且开始时发送速率较慢(slow start)。所以,HTTP 1.0版本的性能比较差。随着网页加载的外部资源越来越多,这个问题就愈发突出了。<br>为了解决这个问题,有些浏览器在请求时,用了一个非标准的Connection字段。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Connection: keep-alive</div></pre></td></tr></table></figure></p>
<p>这个字段要求服务器不要关闭TCP连接,以便其他请求复用。服务器同样回应这个字段。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Connection: keep-alive</div></pre></td></tr></table></figure></p>
<p>一个可以复用的TCP连接就建立了,直到客户端或服务器主动关闭连接。但是,这不是标准字段,不同实现的行为可能不一致,因此不是根本的解决办法。</p>
<h3 id="三、HTTP-1-1"><a href="#三、HTTP-1-1" class="headerlink" title="三、HTTP/1.1"></a>三、HTTP/1.1</h3><p>1997年1月,HTTP/1.1 版本发布,只比 1.0 版本晚了半年。它进一步完善了 HTTP 协议,一直用到了20年后的今天,直到现在还是最流行的版本。<br>3.1 持久连接<br>1.1 版的最大变化,就是引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive。<br>客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Connection: close</div></pre></td></tr></table></figure></p>
<p>目前,对于同一个域名,大多数浏览器允许同时建立6个持久连接。<br>3.2 管道机制<br>1.1 版还引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。<br>举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求。管道机制则是允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求。<br>3.3 Content-Length 字段<br>一个TCP连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是Content-length字段的作用,声明本次回应的数据长度。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Content-Length: 3495</div></pre></td></tr></table></figure></p>
<p>上面代码告诉浏览器,本次回应的长度是3495个字节,后面的字节就属于下一个回应了。<br>在1.0版中,Content-Length字段不是必需的,因为浏览器发现服务器关闭了TCP连接,就表明收到的数据包已经全了。<br>3.4 分块传输编码<br>使用Content-Length字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。<br>对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用”流模式”(stream)取代”缓存模式”(buffer)。<br>因此,1.1版规定可以不使用Content-Length字段,而使用”分块传输编码”(chunked transfer encoding)。只要请求或回应的头信息有Transfer-Encoding字段,就表明回应将由数量未定的数据块组成。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Transfer-Encoding: chunked</div></pre></td></tr></table></figure></p>
<p>每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了。下面是一个例子。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line">HTTP/1.1 200 OK</div><div class="line">Content-Type: text/plain</div><div class="line">Transfer-Encoding: chunked</div><div class="line"></div><div class="line">25</div><div class="line">This is the data <span class="keyword">in</span> the first chunk</div><div class="line"></div><div class="line">1C</div><div class="line">and this is the second one</div><div class="line"></div><div class="line">3</div><div class="line">con</div><div class="line"></div><div class="line">8</div><div class="line">sequence</div><div class="line"></div><div class="line">0</div></pre></td></tr></table></figure></p>
<p>3.5 其他功能<br>1.1版还新增了许多动词方法:PUT、PATCH、HEAD、 OPTIONS、DELETE。<br>另外,客户端请求的头信息新增了Host字段,用来指定服务器的域名。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">Host: www.example.com</div></pre></td></tr></table></figure></p>
<p>有了Host字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。<br>3.6 缺点<br>虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为”队头堵塞”(Head-of-line blocking)。<br>为了避免这个问题,只有两种方法:一是减少请求数,二是同时多开持久连接。这导致了很多的网页优化技巧,比如合并脚本和样式表、将图片嵌入CSS代码、域名分片(domain sharding)等等。如果HTTP协议设计得更好一些,这些额外的工作是可以避免的。</p>
<h3 id="四、SPDY-协议"><a href="#四、SPDY-协议" class="headerlink" title="四、SPDY 协议"></a>四、SPDY 协议</h3><p>2009年,谷歌公开了自行研发的 SPDY 协议,主要解决 HTTP/1.1 效率不高的问题。<br>这个协议在Chrome浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。</p>
<h3 id="五、HTTP-2"><a href="#五、HTTP-2" class="headerlink" title="五、HTTP/2"></a>五、HTTP/2</h3><p>2015年,HTTP/2 发布。它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。<br>5.1 二进制协议<br>HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为”帧”(frame):头信息帧和数据帧。<br>二进制协议的一个好处是,可以定义额外的帧。HTTP/2 定义了近十种帧,为将来的高级应用打好了基础。如果使用文本实现这种功能,解析数据将会变得非常麻烦,二进制解析则方便得多。<br>5.2 多工<br>HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了”队头堵塞”。<br>举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。<br>这样双向的、实时的通信,就叫做多工(Multiplexing)。<br>5.3 数据流<br>因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。<br>HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。<br>数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。<br>客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。<br>5.4 头信息压缩<br>HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。<br>HTTP/2 对这一点做了优化,引入了头信息压缩机制(header compression)。一方面,头信息使用gzip或compress压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了。<br>5.5 服务器推送<br>HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。<br>常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。</p>
</div>
<div>
</div>
<div>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">
<a class="post-title-link" href="/2017/02/22/sublime_text3/" itemprop="url">
sublime text3开发环境
</a>
</h1>
<div class="post-meta">
<span class="post-time">
<span class="post-meta-item-icon">
<i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">发表于</span>
<time itemprop="dateCreated" datetime="2017-02-22T10:49:15+08:00" content="2017-02-22">
2017-02-22
</time>
</span>
<span class="post-category" >
|
<span class="post-meta-item-icon">
<i class="fa fa-folder-o"></i>
</span>
<span class="post-meta-item-text">分类于</span>
<span itemprop="about" itemscope itemtype="https://schema.org/Thing">
<a href="/categories/others/" itemprop="url" rel="index">
<span itemprop="name">others</span>
</a>
</span>
</span>
<span class="post-comments-count">
|
<a href="/2017/02/22/sublime_text3/#comments" itemprop="discussionUrl">
<span class="post-comments-count ds-thread-count" data-thread-key="2017/02/22/sublime_text3/" itemprop="commentsCount"></span>
</a>
</span>
<span id="/2017/02/22/sublime_text3/" class="leancloud_visitors" data-flag-title="sublime text3开发环境">
|
<span class="post-meta-item-icon">
<i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读次数 </span>
<span class="leancloud-visitors-count"></span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">