-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
750 lines (519 loc) · 50.1 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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
<link rel="apple-touch-icon" sizes="180x180" href="/T-Zhan/images/apple-touch-icon-next.png">
<link rel="icon" type="image/png" sizes="32x32" href="/T-Zhan/images/favicon-32x32-next.png">
<link rel="icon" type="image/png" sizes="16x16" href="/T-Zhan/images/favicon-16x16-next.png">
<link rel="mask-icon" href="/T-Zhan/images/logo.svg" color="#222">
<link rel="stylesheet" href="/T-Zhan/css/main.css">
<link rel="stylesheet" href="/T-Zhan/lib/font-awesome/css/all.min.css">
<script id="hexo-configurations">
var NexT = window.NexT || {};
var CONFIG = {"hostname":"chaoqunzhan.github.io","root":"/T-Zhan/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
</script>
<meta property="og:type" content="website">
<meta property="og:title" content="前端T站">
<meta property="og:url" content="https://chaoqunzhan.github.io/T-Zhan/index.html">
<meta property="og:site_name" content="前端T站">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="Tab Zhan">
<meta name="twitter:card" content="summary">
<link rel="canonical" href="https://chaoqunzhan.github.io/T-Zhan/">
<script id="page-configurations">
// https://hexo.io/docs/variables.html
CONFIG.page = {
sidebar: "",
isHome : true,
isPost : false,
lang : 'en'
};
</script>
<title>前端T站</title>
<noscript>
<style>
.use-motion .brand,
.use-motion .menu-item,
.sidebar-inner,
.use-motion .post-block,
.use-motion .pagination,
.use-motion .comments,
.use-motion .post-header,
.use-motion .post-body,
.use-motion .collection-header { opacity: initial; }
.use-motion .site-title,
.use-motion .site-subtitle {
opacity: initial;
top: initial;
}
.use-motion .logo-line-before i { left: initial; }
.use-motion .logo-line-after i { right: initial; }
</style>
</noscript>
</head>
<body itemscope itemtype="http://schema.org/WebPage">
<div class="container use-motion">
<div class="headband"></div>
<header class="header" itemscope itemtype="http://schema.org/WPHeader">
<div class="header-inner"><div class="site-brand-container">
<div class="site-nav-toggle">
<div class="toggle" aria-label="Toggle navigation bar">
<span class="toggle-line toggle-line-first"></span>
<span class="toggle-line toggle-line-middle"></span>
<span class="toggle-line toggle-line-last"></span>
</div>
</div>
<div class="site-meta">
<a href="/T-Zhan/" class="brand" rel="start">
<span class="logo-line-before"><i></i></span>
<h1 class="site-title">前端T站</h1>
<span class="logo-line-after"><i></i></span>
</a>
</div>
<div class="site-nav-right">
<div class="toggle popup-trigger">
</div>
</div>
</div>
<nav class="site-nav">
<ul id="menu" class="main-menu menu">
<li class="menu-item menu-item-home">
<a href="/T-Zhan/" rel="section"><i class="fa fa-home fa-fw"></i>Home</a>
</li>
<li class="menu-item menu-item-about">
<a href="/T-Zhan/about/" rel="section"><i class="fa fa-user fa-fw"></i>About</a>
</li>
<li class="menu-item menu-item-tags">
<a href="/T-Zhan/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>Tags</a>
</li>
<li class="menu-item menu-item-categories">
<a href="/T-Zhan/categories/" rel="section"><i class="fa fa-th fa-fw"></i>Categories</a>
</li>
<li class="menu-item menu-item-archives">
<a href="/T-Zhan/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>Archives</a>
</li>
</ul>
</nav>
</div>
</header>
<div class="back-to-top">
<i class="fa fa-arrow-up"></i>
<span>0%</span>
</div>
<main class="main">
<div class="main-inner">
<div class="content-wrap">
<div class="content index posts-expand">
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="en">
<link itemprop="mainEntityOfPage" href="https://chaoqunzhan.github.io/T-Zhan/2021/08/03/%E5%BE%AE%E5%89%8D%E7%AB%AF%E5%AD%A6%E4%B9%A0/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/T-Zhan/images/logo.png">
<meta itemprop="name" content="Tab Zhan">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="前端T站">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/T-Zhan/2021/08/03/%E5%BE%AE%E5%89%8D%E7%AB%AF%E5%AD%A6%E4%B9%A0/" class="post-title-link" itemprop="url">微前端学习</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2021-08-03 16:14:38" itemprop="dateCreated datePublished" datetime="2021-08-03T16:14:38+08:00">2021-08-03</time>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="en">
<link itemprop="mainEntityOfPage" href="https://chaoqunzhan.github.io/T-Zhan/2021/08/01/%E5%89%8D%E7%AB%AF%E5%AF%BC%E5%85%A5-%E5%AF%BC%E5%87%BAEXCEL-SheetJs/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/T-Zhan/images/logo.png">
<meta itemprop="name" content="Tab Zhan">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="前端T站">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/T-Zhan/2021/08/01/%E5%89%8D%E7%AB%AF%E5%AF%BC%E5%85%A5-%E5%AF%BC%E5%87%BAEXCEL-SheetJs/" class="post-title-link" itemprop="url">前端导入/导出EXCEL-SheetJs</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2021-08-01 21:24:58 / Modified: 21:25:58" itemprop="dateCreated datePublished" datetime="2021-08-01T21:24:58+08:00">2021-08-01</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">In</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/T-Zhan/categories/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/" itemprop="url" rel="index"><span itemprop="name">前端框架</span></a>
</span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<p>在日常开发中,遇到批量导入的情况,通常是将文件上传至后端来解析excel文件流。这种做法会占用一定的带宽和后端性能,SheetJS是用于多种电子表格格式的解析器和编写器。通过使用SheetJS,前端可以直接实现.xlsx, .xlsm, .txt, .csv, .html等文件的导出和导入,比如,将execl文件转化为json,或者将json导出为execl。当然这一定程度上也会消耗前端的性能,但这对于数据安全更有保障,而且也有利于前后端交互的统一性。本文将介绍如何使用sheetJS,实现纯前端的execl数据导出和导入,并简单介绍sheetJS相关概念:</p>
<p>sheetJS社区版js-xlsx地址为:<a target="_blank" rel="noopener" href="https://github.com/SheetJS/sheetjs">https://github.com/SheetJS/sheetjs</a></p>
<h3 id="相关概念"><a href="#相关概念" class="headerlink" title="相关概念"></a>相关概念</h3><p>execl与js-xlsx之间的关系,这两者有着极强的对应关系,如下:</p>
<table>
<thead>
<tr>
<th>execl名词</th>
<th>js-xlsx类型</th>
</tr>
</thead>
<tbody><tr>
<td>工作簿</td>
<td>workBook</td>
</tr>
<tr>
<td>工作表</td>
<td>Sheets</td>
</tr>
<tr>
<td>单元格</td>
<td>cell</td>
</tr>
</tbody></table>
<p>就像我们熟悉的execl文件一样,工作簿里有可能存在多个工作表,每个工作表里也很多单元格,js-xlsx有workBook对象,里面可以存在和创建Sheets,在Sheets对象里还存在很多的cell元素。</p>
<h3 id="js-xlsx的安装"><a href="#js-xlsx的安装" class="headerlink" title="js-xlsx的安装"></a>js-xlsx的安装</h3><p>参考官方文档:</p>
<p>script引入:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><script lang=<span class="string">"javascript"</span> src=<span class="string">"dist/xlsx.full.min.js"</span>></script></span><br></pre></td></tr></table></figure>
<p>CDN引入:</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//npm方式</span></span><br><span class="line">$ npm install xlsx</span><br><span class="line"></span><br><span class="line"><span class="comment">//bower方式</span></span><br><span class="line">$ bower install js-xlsx</span><br></pre></td></tr></table></figure>
<h3 id="Json数据导出为execl文件"><a href="#Json数据导出为execl文件" class="headerlink" title="Json数据导出为execl文件"></a>Json数据导出为execl文件</h3><p>为了把json数据导出为execl文件,我们需要执行三个步骤:</p>
<ol>
<li>创建工作簿,就是创建一个workBook对象;</li>
<li>在工作簿里新建工作表,就是新建Sheets对象;</li>
<li>把数据写入表格的单元格里,就是把Json数据写入cell中;</li>
</ol>
<p>代码示例如下:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//data为json数据,</span></span><br><span class="line"><span class="function"><span class="title">Export</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">let</span> wb = XLSX.utils.book_new(), <span class="comment">//新建工作簿</span></span><br><span class="line"> sheet = {},</span><br><span class="line"> sheet = XLSX.utils.json_to_sheet(data, {<span class="attr">skipHeader</span>:<span class="literal">true</span>}); <span class="comment">//新建工作表</span></span><br><span class="line"> XLSX.utils.book_append_sheet(wb, sheet, <span class="string">'name'</span>); <span class="comment">//工作表添加到工作簿中</span></span><br><span class="line"> XLSX.writeFile(wb, <span class="string">'name.xlsx'</span>);</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p><code>XLSX.utils.json_to_sheet</code>获取对象数组并且返回一张基于对象自动生成”headers”的工作表。默认的列顺序由第一次出现的字段决定,这些字段通过使用<code>Object.keys</code>得到,不过可以使用选项参数覆盖。</p>
<table>
<thead>
<tr>
<th>Option Name</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>header</code></td>
<td></td>
<td>使用指定的列顺序 (默认 <code>Object.keys</code>)</td>
</tr>
<tr>
<td><code>dateNF</code></td>
<td>FMT 14</td>
<td>字符串输出使用指定的日期格式</td>
</tr>
<tr>
<td><code>cellDates</code></td>
<td>false</td>
<td>存储日期为类型 <code>d</code> (默认是 <code>n</code>)</td>
</tr>
<tr>
<td><code>skipHeader</code></td>
<td>false</td>
<td>如果值为true, 输出不包含header行</td>
</tr>
</tbody></table>
<p>原始的表单不能以明显的方法复制,因为JS对象的keys必须是独一无二的。之后用<code>e_1</code> 和 <code>S_1</code>替换第二个<code>e</code> 和 <code>S</code>。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">var ws = XLSX.utils.json_to_sheet([</span><br><span class="line"> { S:1, h:2, e:3, e_1:4, t:5, J:6, S_1:7 },</span><br><span class="line"> { S:2, h:3, e:4, e_1:5, t:6, J:7, S_1:8 }</span><br><span class="line">], {header:["S","h","e","e_1","t","J","S_1"]});</span><br></pre></td></tr></table></figure>
<p>或者可以跳过header行:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">var ws = XLSX.utils.json_to_sheet([</span><br><span class="line"> { A:"S", B:"h", C:"e", D:"e", E:"t", F:"J", G:"S" },</span><br><span class="line"> { A: 1, B: 2, C: 3, D: 4, E: 5, F: 6, G: 7 },</span><br><span class="line"> { A: 2, B: 3, C: 4, D: 5, E: 6, F: 7, G: 8 }</span><br><span class="line">], {header:["A","B","C","D","E","F","G"], skipHeader:true});</span><br></pre></td></tr></table></figure>
<p><code>skipHeader:true</code>导出会跳过表头字段。</p>
<p>除了<code>json_to_sheet</code>,还有其他的数据导入Sheets对象的方法:</p>
<ul>
<li><code>aoa_to_sheet</code> 把转换JS数据数组的数组为工作表。</li>
<li><code>table_to_sheet</code> 把DOM TABLE元素转换为工作表。</li>
<li><code>sheet_add_aoa</code> 把JS数据数组的数组添加到已存在的工作表中。</li>
<li><code>sheet_add_json</code> 把JS对象数组添加到已存在的工作表中。</li>
</ul>
<p>详情查看文档:<a target="_blank" rel="noopener" href="https://github.com/SheetJS/sheetjs">https://github.com/SheetJS/sheetjs</a></p>
<p><code>XLSX.utils.book_append_sheet</code>用来把工作表添加到工作簿中,<code>XLSX.utils.book_append_sheet(wb, sheet,name)</code>方法有三个参数:</p>
<ul>
<li><p>wb: 要写入的工作簿</p>
</li>
<li><p>sheet:工作表</p>
</li>
<li><p>name:工作表的名称</p>
</li>
</ul>
<p><code>XLSX.write(wb, write_opts)</code> 用来写入工作簿 <code>wb</code>。 <code>XLSX.writeFile(wb, filename, write_opts)</code> 把 <code>wb</code> 写入到特定的文件 <code>filename</code> 中。如果是基于浏览器的环境,此函数会强制浏览器端下载。 <code>XLSX.writeFileAsync(filename, wb, o, cb)</code> 把 <code>wb</code> 写入到特定的文件 <code>filename</code> 中。如果 <code>o</code> 被省略,写入函数会使用第三个参数作为回调函数。其中<code>write_opts</code>是写入配置,可以配置包括输出数据编码、把字节存储为类型<code>d</code>等等属性。<code>filename</code>就是文件名了。</p>
<h3 id="excel文件读取为Json数据"><a href="#excel文件读取为Json数据" class="headerlink" title="excel文件读取为Json数据"></a>excel文件读取为Json数据</h3><p>首先,用到iview-UI的Upload组件,然后在组件的before-upload钩子(上传前)中执行数据解析。</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></pre></td><td class="code"><pre><span class="line">//.html</span><br><span class="line"><span class="tag"><<span class="name">Upload</span> <span class="attr">class</span>=<span class="string">"ml10"</span> <span class="attr">:action</span>=<span class="string">"uploadUrl"</span> <span class="attr">:format</span>=<span class="string">"['xlsx', 'xls']"</span> <span class="attr">name</span>=<span class="string">"file"</span> <span class="attr">:before-upload</span>=<span class="string">"beforeUpload"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">Button</span> <span class="attr">icon</span>=<span class="string">"ios-cloud-upload-outline"</span>></span>导入修改<span class="tag"></<span class="name">Button</span>></span></span><br><span class="line"><span class="tag"></<span class="name">Upload</span>></span></span><br></pre></td></tr></table></figure>
<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></pre></td><td class="code"><pre><span class="line"><span class="comment">//.js</span></span><br><span class="line"><span class="function"><span class="title">beforeUpload</span>(<span class="params">file, fileList</span>)</span>{</span><br><span class="line"> <span class="keyword">const</span> f = file;</span><br><span class="line"> <span class="keyword">let</span> reader = <span class="keyword">new</span> FileReader(); <span class="comment">//创建FileReader对象</span></span><br><span class="line"> reader.readAsArrayBuffer(f); <span class="comment">//读取指定的Blob中的内容</span></span><br><span class="line"> reader.onload = <span class="function"><span class="keyword">function</span> (<span class="params">e</span>) </span>{ <span class="comment">//读取file完成后</span></span><br><span class="line"> <span class="keyword">let</span> data = e.target.result;</span><br><span class="line"> <span class="keyword">let</span> workbook = XLSX.read(data, {</span><br><span class="line"> <span class="attr">type</span>: <span class="string">'array'</span></span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">let</span> first_worksheet = workbook.Sheets[workbook.SheetNames[<span class="number">0</span>]]; <span class="comment">//获取第一张数据表</span></span><br><span class="line"> <span class="keyword">var</span> jsonArr = XLSX.utils.sheet_to_json(first_worksheet, {<span class="attr">header</span>:<span class="number">1</span>}); <span class="comment">//把工作表转化为Json</span></span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'jsonArr:'</span>,jsonArr)</span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><code>FileReader</code> 是一个常用的web API,<code>FileReader</code> 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用File和Blob对象指定要读取的文件或数据。<code>FileReader.onload</code>处理<code>load</code>事件,该事件在读取操作完成时触发。<code>reader.readAsArrayBuffer</code>开始读取指定的Blob中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer数据对象。</p>
<p><code>XLSX.read(data, read_opts)</code> 用来解析数据 <code>data</code>。 <code>XLSX.readFile(filename, read_opts)</code> 用来读取文件名 <code>filename</code> 并且解析。<code>read_opts</code>为读取配置,可以用来配置输入数据编码等。<code>XLSX.utils.sheet_to_json</code>把工作表转化为Json。</p>
<p>其实SheetJS除了简单的导入和导出excel文件之外,还支持其他的文件类型,而且还能设置文件样式等,功能强大,慢慢挖掘!</p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
<article itemscope itemtype="http://schema.org/Article" class="post-block" lang="en">
<link itemprop="mainEntityOfPage" href="https://chaoqunzhan.github.io/T-Zhan/2021/08/01/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/">
<span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
<meta itemprop="image" content="/T-Zhan/images/logo.png">
<meta itemprop="name" content="Tab Zhan">
<meta itemprop="description" content="">
</span>
<span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
<meta itemprop="name" content="前端T站">
</span>
<header class="post-header">
<h2 class="post-title" itemprop="name headline">
<a href="/T-Zhan/2021/08/01/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/" class="post-title-link" itemprop="url">前端性能优化学习</a>
</h2>
<div class="post-meta">
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-calendar"></i>
</span>
<span class="post-meta-item-text">Posted on</span>
<time title="Created: 2021-08-01 13:15:38 / Modified: 18:11:55" itemprop="dateCreated datePublished" datetime="2021-08-01T13:15:38+08:00">2021-08-01</time>
</span>
<span class="post-meta-item">
<span class="post-meta-item-icon">
<i class="far fa-folder"></i>
</span>
<span class="post-meta-item-text">In</span>
<span itemprop="about" itemscope itemtype="http://schema.org/Thing">
<a href="/T-Zhan/categories/web/" itemprop="url" rel="index"><span itemprop="name">web</span></a>
</span>
</span>
</div>
</header>
<div class="post-body" itemprop="articleBody">
<h2 id="1、浏览器架构(chrome的多进程架构)"><a href="#1、浏览器架构(chrome的多进程架构)" class="headerlink" title="1、浏览器架构(chrome的多进程架构)"></a>1、浏览器架构(chrome的多进程架构)</h2><ul>
<li>Browser 进程:打开浏览器后,始终只有一个。该进程有 UI 线程、Network 线程、Storage 线程等。用户输入 url 后,首先是 Browser 进程进行响应和请求服务器获取数据。然后传递给 Renderer 进程。</li>
<li>Renderer 进程:每一个 tab 一个,负责 html、css、js 执行的整个过程。<strong>前端性能优化也与这个进程有关</strong>。</li>
<li>Plugin 进程:与浏览器插件相关,例如 flash 等。</li>
<li>GPU 进程:浏览器共用一个。主要负责把 Renderer 进程中绘制好的 tile 位图作为纹理上传到 GPU,并调用 GPU 相关方法把纹理 draw 到屏幕上。</li>
</ul>
<p>浏览器每个tab跑在不同的进程中,如果其中一个tab挂了,不会影响其他的tab。多进程会浪费内存,每个进程相同的基础架构不能共用,所以chrome会限制启动的进程数量。当打开的tab页过多时,会把同一个网站的tab放在同一个进程中。</p>
<h2 id="2、页面渲染相关进程"><a href="#2、页面渲染相关进程" class="headerlink" title="2、页面渲染相关进程"></a>2、页面渲染相关进程</h2><p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/Prcess.jpg?token=AHPD6DX7JN2SNJFG74HVSALBAZZFE"></p>
<h4 id="2-1-Render-Process"><a href="#2-1-Render-Process" class="headerlink" title="2.1 Render Process"></a>2.1 Render Process</h4><h5 id="Renderer-进程:包括-3-个线程。合成线程(Compositor-Thread)、主线程(Main-Thread)、Compositor-Tile-Worker。"><a href="#Renderer-进程:包括-3-个线程。合成线程(Compositor-Thread)、主线程(Main-Thread)、Compositor-Tile-Worker。" class="headerlink" title="Renderer 进程:包括 3 个线程。合成线程(Compositor Thread)、主线程(Main Thread)、Compositor Tile Worker。"></a>Renderer 进程:包括 3 个线程。合成线程(Compositor Thread)、主线程(Main Thread)、Compositor Tile Worker。</h5><ul>
<li>Compositor Thread:首先接收 vsync 信号(vsync 信号是指操作系统指示浏览器去绘制新的帧),任何事件都会先到达 Compositor 线程。如果主线程没有绑定事件,那么 Compositor 线程将避免进入主线程,并尝试将输入转换为屏幕上的移动。它将更新的图层位置信息作为帧通过 GPU 线程传递给 GPU 进行绘制。</li>
<li>Main Thread:<strong>主线程就是我们前端工程师熟知的线程,这里会执行解析 Html、样式计算、布局、绘制、合成等动作。所以关于性能的问题,都发生在了这里。所以应该重点关注这里</strong>。</li>
<li>Compositor Tile Worker:由合成线程产生一个或多个 worker 来处理光栅化的工作。</li>
</ul>
<h5 id="主线程:"><a href="#主线程:" class="headerlink" title="主线程:"></a>主线程:</h5><p>Recal Styles 和 Layout 指向了 requestAnimationFrame,这意味着有 Forced Synchronous Layout (or Styles)(强制回流和重绘)发生。</p>
<p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/render-process.jpg?token=AHPD6DWYZPR45ZRRDPZ6RFDBAZZHK" alt="图片"></p>
<p>主线程的执行顺序如上图,但是如果只需要Paint,那么就不会有前面的步骤了。</p>
<ul>
<li><p>Parse HTML: 解析HTML,使之变成DOM(Document Object Model);在解析HTML过程中会找到子资源(图像,CSS,JS等 ),浏览器的预加载程序会把这些请求发送到network线程中进行资源加载。如果遇到<code><script></code>标签,会停止HTML解析,因为JS会影响DOM的结构。</p>
</li>
<li><p>Recalc Style: 遇到CSS资源会加载CSS代码,来确定每个DOM节点的计算样式。即使没有样式,浏览器也会提供默认的样式。</p>
</li>
<li><p>Layout: 找到所有元素的几何关系,生成布局树(Render Tree)。</p>
</li>
<li><p>Paint:遍历布局树生成绘画记录,记录元素绘制的先后顺序。</p>
</li>
<li><p>Composite: 将页面分为若干层,分别进行光栅化,在根据用户滚动的页面来按需合成新的帧来展示效果。</p>
</li>
</ul>
<p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/browser-working-process.png?token=AHPD6DWLSM4Z6B3PEEWVBS3BAZZJW" alt="浏览器工作大致流程"></p>
<p>主流浏览器的屏幕刷新率是60Hz,所以渲染一帧的时间必须保证在16ms以内才能不掉帧。</p>
<p>正常的情况下是:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">执行 JS -> 空闲 -> 绘制(16ms)-> 执行 JS -> 空闲 -> 绘制(32ms)-> ...</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">执行很多 JS...(20ms)-> 空闲 -> 绘制(32ms)-> ...</span><br></pre></td></tr></table></figure>
<p>这里执行的JS可以看成是Recal Styles 和 Layout 到 requestAnimationFrame过程,进行了很多次,造成时间的占用。<strong>所以让主线程执行的过程尽量少能达到性能优化的效果</strong>。减少页面的重绘,避免使用会让页面重绘的CSS。</p>
<h4 id="2-2-GPU-Process"><a href="#2-2-GPU-Process" class="headerlink" title="2.2 GPU Process"></a>2.2 GPU Process</h4><p>GPU 进程:只有 GPU 线程,负责接收从 Renderer 进程中的 Compositor Thread 传过来的纹理,显示到屏幕上。</p>
<h2 id="3、经典回顾"><a href="#3、经典回顾" class="headerlink" title="3、经典回顾"></a>3、经典回顾</h2><p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/35%E5%86%9B%E8%A7%84.png" alt="图片"></p>
<h2 id="4、性能指标"><a href="#4、性能指标" class="headerlink" title="4、性能指标"></a>4、性能指标</h2><h4 id="4-1-Google-和-W3C-性能工作组提供的几种性能指标:"><a href="#4-1-Google-和-W3C-性能工作组提供的几种性能指标:" class="headerlink" title="4.1 Google 和 W3C 性能工作组提供的几种性能指标:"></a>4.1 Google 和 W3C 性能工作组提供的几种性能指标:</h4><ul>
<li><strong><a target="_blank" rel="noopener" href="https://web.dev/fcp/">First contentful paint (FCP)</a>:</strong> 测量页面开始加载到某一块内容显示在页面上的时间。</li>
<li><strong><a target="_blank" rel="noopener" href="https://web.dev/lcp/">Largest contentful paint (LCP)</a>:</strong> 测量页面开始加载到最大文本块内容或图片显示在页面中的时间。</li>
<li><strong><a target="_blank" rel="noopener" href="https://web.dev/fid/">First input delay (FID)</a>:</strong> 测量用户首次与网站进行交互(例如点击一个链接、按钮、js 自定义控件)到浏览器真正进行响应的时间。</li>
<li><strong><a target="_blank" rel="noopener" href="https://web.dev/tti/">Time to Interactive (TTI)</a>:</strong> 测量从页面加载到可视化呈现、页面初始化脚本已经加载,并且可以可靠地快速响应用户的时间。</li>
<li><strong><a target="_blank" rel="noopener" href="https://web.dev/tbt/">Total blocking time (TBT)</a>:</strong> 测量从 FCP 到 TTI 之间的时间,这个时间内主线程被阻塞无法响应用户输入。</li>
<li><strong><a target="_blank" rel="noopener" href="https://web.dev/cls/">Cumulative layout shift (CLS)</a>:</strong> 测量从页面开始加载到状态变为隐藏过程中,发生不可预期的 layout shifts 的累积分数。</li>
</ul>
<h4 id="4-2-核心指标"><a href="#4-2-核心指标" class="headerlink" title="4.2 核心指标"></a>4.2 核心指标</h4><p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/%E6%8C%87%E6%A0%87.png?token=AHPD6DRBA6V5VQSM7L6NECDBAZZPY" alt="图片"></p>
<p>Google 官方提供了一个<a target="_blank" rel="noopener" href="https://github.com/GoogleChrome/web-vitals">web-vitals</a>库,线上或本地都可以测量上面提到的 3 个指标:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {getCLS, getFID, getLCP} <span class="keyword">from</span> <span class="string">'web-vitals'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sendToAnalytics</span>(<span class="params">metric</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> body = <span class="built_in">JSON</span>.stringify(metric);</span><br><span class="line"> <span class="comment">// Use `navigator.sendBeacon()` if available, falling back to `fetch()`.</span></span><br><span class="line"> (navigator.sendBeacon && navigator.sendBeacon(<span class="string">'/analytics'</span>, body)) ||</span><br><span class="line"> fetch(<span class="string">'/analytics'</span>, {body, <span class="attr">method</span>: <span class="string">'POST'</span>, <span class="attr">keepalive</span>: <span class="literal">true</span>});</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">getCLS(sendToAnalytics);</span><br><span class="line">getFID(sendToAnalytics);</span><br><span class="line">getLCP(sendToAnalytics);</span><br></pre></td></tr></table></figure>
<h5 id="4-2-1-PerformanceObserver-性能观察者"><a href="#4-2-1-PerformanceObserver-性能观察者" class="headerlink" title="4.2.1 PerformanceObserver 性能观察者"></a>4.2.1 PerformanceObserver 性能观察者</h5><p><code>PerformanceObserver</code>是浏览器内部对<code>Performance</code>实现的观察者模式,也是现代浏览器支持的几个 <code>Observer</code> 之一。</p>
<ul>
<li>避免不知道性能事件啥时候会发生,需要重复轮训<code>timeline</code>获取记录。</li>
<li>避免产生重复的逻辑去获取不同的性能数据指标</li>
<li>避免其他资源需要操作浏览器性能缓冲区时产生竞态关系。</li>
</ul>
<p><code>PerformanceObserver</code>使用:</p>
<ol>
<li>创建观察者</li>
<li>定义回调函数事件</li>
<li>定义要观察的目标对象</li>
</ol>
<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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> observer = <span class="keyword">new</span> PerformanceObserver(callback); </span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> callback = <span class="function">(<span class="params">list, observer</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> entries = list.getEntries();</span><br><span class="line"> entries.forEach(<span class="function">(<span class="params">entry</span>) =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Name:'</span>+entry.name+<span class="string">', Type: '</span>+entry.entryType +<span class="string">', Start: '</span>+entry.startTime+<span class="string">', Duration: '</span>+entry.duration+<span class="string">'\n'</span>); });</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">observer.observe({<span class="attr">entryTypes</span>: [<span class="string">"entryTypes"</span>]});</span><br></pre></td></tr></table></figure>
<p>其中callback中的<code>list</code>都是一个完整的<code>PerformanceObserverEntryList</code>对象:</p>
<h5 id="4-2-2-LCP"><a href="#4-2-2-LCP" class="headerlink" title="4.2.2 LCP"></a>4.2.2 LCP</h5><p>Largest contentful paint (LCP):最大内容块显示的时间。直接使用JS API测量,除了IE大部分浏览器都支持。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">//打开对应页面,在控制台输入</span></span><br><span class="line"><span class="keyword">new</span> PerformanceObserver(<span class="function">(<span class="params">entryList</span>) =></span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> entry <span class="keyword">of</span> entryList.getEntries()) {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'LCP candidate:'</span>, entry.startTime, entry);</span><br><span class="line"> }</span><br><span class="line">}).observe({<span class="attr">type</span>: <span class="string">'largest-contentful-paint'</span>, <span class="attr">buffered</span>: <span class="literal">true</span>});</span><br></pre></td></tr></table></figure>
<p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/LCP.png?token=AHPD6DR5BEPXHGTZW4MRGCDBAZZSA" alt="image-20210715190858508"></p>
<p>优化点:</p>
<ul>
<li>减少大文件的加载;</li>
<li>减少服务端响应时间;</li>
</ul>
<h5 id="4-2-3-FID"><a href="#4-2-3-FID" class="headerlink" title="4.2.3 FID"></a>4.2.3 FID</h5><p>First Input Delay(FID),指从浏览器接收到了用户输入,到浏览器对用户的输入进行响应的延迟时间。当 FID 的时间为 100ms 或以内,则为 Good。new </p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">PerformanceObserver(<span class="function">(<span class="params">entryList</span>) =></span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> entry <span class="keyword">of</span> entryList.getEntries()) {</span><br><span class="line"> <span class="keyword">const</span> delay = entry.processingStart - entry.startTime;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'FID candidate:'</span>, delay, entry);</span><br><span class="line"> }</span><br><span class="line">}).observe({<span class="attr">type</span>: <span class="string">'first-input'</span>, <span class="attr">buffered</span>: <span class="literal">true</span>});</span><br></pre></td></tr></table></figure>
<p>优化点:</p>
<p>减少主线程的工作,因为FID主要是主线程繁忙引起的用户响应不及时。</p>
<h5 id="4-2-3-GLS"><a href="#4-2-3-GLS" class="headerlink" title="4.2.3 GLS"></a>4.2.3 GLS</h5><p>Cumulative Layout Shift,意外布局移动, 浏览器会监控两桢之间发生移动的不稳定元素。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> cls = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">new</span> PerformanceObserver(<span class="function">(<span class="params">entryList</span>) =></span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> entry <span class="keyword">of</span> entryList.getEntries()) {</span><br><span class="line"> <span class="keyword">if</span> (!entry.hadRecentInput) {</span><br><span class="line"> cls += entry.value;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'Current CLS value:'</span>, cls, entry);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}).observe({<span class="attr">type</span>: <span class="string">'layout-shift'</span>, <span class="attr">buffered</span>: <span class="literal">true</span>});</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>优化点:</p>
<p>减少页面的重绘</p>
<h4 id="4-3-性能工具"><a href="#4-3-性能工具" class="headerlink" title="4.3 性能工具"></a>4.3 性能工具</h4><h5 id="4-3-1-Lighthouse"><a href="#4-3-1-Lighthouse" class="headerlink" title="4.3.1 Lighthouse"></a>4.3.1 Lighthouse</h5><p>打开 F12,就可以看到 Lighthouse,点击 Generate Report,即可生成报告。当然也可以添加 chrome 插件使用。</p>
<p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/lightHouse.png?token=AHPD6DUOGOTKYWD4HBXBA23BAZZT2" alt="image-20210719143708018"></p>
<h5 id="4-3-2-PageSpeed-Insights"><a href="#4-3-2-PageSpeed-Insights" class="headerlink" title="4.3.2 PageSpeed Insights"></a>4.3.2 PageSpeed Insights</h5><p>一个可以分析线上和实验室数据的工具。它是根据线上环境用户真实的数据(在 Chrome UX 报告中)和 Lighthouse 结合出一份报告。和 Lighthouse 类似,它也会给出一些分析建议,可以知道页面的 Core Web Vitals 是否达标。</p>
<p><a target="_blank" rel="noopener" href="https://developers.google.com/speed/pagespeed/insights/">https://developers.google.com/speed/pagespeed/insights/</a></p>
<h5 id="4-3-3-CrUX"><a href="#4-3-3-CrUX" class="headerlink" title="4.3.3 CrUX"></a>4.3.3 CrUX</h5><p>Chrome UX Report (CrUX)是指汇聚了成千上万条用户体验数据的数据报告集,它是经过用户同意才进行上报的,目前存储在 Google BigQuery 上,可以使用账号登陆进行查询。它测量了所有的 Core Web Vitals 指标。</p>
<h5 id="4-3-4-Performance"><a href="#4-3-4-Performance" class="headerlink" title="4.3.4 Performance"></a>4.3.4 Performance</h5><p>Performance提供几个重要的功能包括:Frame、Timings、Main、Layers、FPS。</p>
<p>Frame:</p>
<p>可以看到每帧的时间,重点关注红色的块,鼠标悬浮可以看到时间和帧率。以下为掉帧的情况。</p>
<p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/rame.png?token=AHPD6DVCM3EZE23FA4JXVLLBAZZVI" alt="image-20210719152247167"></p>
<p>Time:</p>
<p>包括几个指标,DOMContentLoaded Event,First Paint,First Contentful Paint,Largest Contentful Paint,Onload Event。</p>
<p><img src="https://raw.githubusercontent.com/chaoqunzhan/T-Zhan-Origin/master/source/_posts/%E5%89%8D%E7%AB%AF%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E5%AD%A6%E4%B9%A0/ime.png?token=AHPD6DRBBWBY6OHUHTKI3CLBAZZWQ" alt="image-20210719154438322"></p>
<p>Main:</p>
<p>通过Main可以看到主线程的执行过程,避免出现过多的RecalcStyles、Layout(重绘回流)。</p>
<p>Layers:</p>
<p>页面渲染中的生成的一个层,可以查看层的生成原因。</p>
<p>Rendering:</p>
<ul>
<li>Paint flashing:查看哪些内容被重绘了;</li>
<li>Layout Shift Regions 后,进行交互,就可以看到哪些元素进行了布局移动;</li>
</ul>
<p>Memory:</p>
<p>点击录制后,会看到当前状态下内存的占用情况,根据大小排序,我们可以定位到内存占用过多的地方。</p>
<h3 id="参考:"><a href="#参考:" class="headerlink" title="参考:"></a>参考:</h3><p><a target="_blank" rel="noopener" href="https://mp.weixin.qq.com/s/RCJftzmhQbc-b89pU5d32w">https://mp.weixin.qq.com/s/RCJftzmhQbc-b89pU5d32w</a></p>
<p><a target="_blank" rel="noopener" href="https://juejin.cn/post/6844904158131126279">https://juejin.cn/post/6844904158131126279</a></p>
<p><a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/99394757">https://zhuanlan.zhihu.com/p/99394757</a></p>
<p><a target="_blank" rel="noopener" href="https://tsejx.github.io/javascript-guidebook/browser-object-model/browser-working-principle/workflow/">https://tsejx.github.io/javascript-guidebook/browser-object-model/browser-working-principle/workflow/</a></p>
<p><a target="_blank" rel="noopener" href="http://kmanong.top/kmn/qxw/form/article?id=62445&cate=52">http://kmanong.top/kmn/qxw/form/article?id=62445&cate=52</a></p>
<p><a target="_blank" rel="noopener" href="https://web.dev/user-centric-performance-metrics/?utm_source=devtools">https://web.dev/user-centric-performance-metrics/?utm_source=devtools</a></p>
</div>
<footer class="post-footer">
<div class="post-eof"></div>
</footer>
</article>
</div>
<script>
window.addEventListener('tabs:register', () => {
let { activeClass } = CONFIG.comments;
if (CONFIG.comments.storage) {
activeClass = localStorage.getItem('comments_active') || activeClass;
}
if (activeClass) {
let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
if (activeTab) {
activeTab.click();
}
}
});
if (CONFIG.comments.storage) {
window.addEventListener('tabs:click', event => {
if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
let commentClass = event.target.classList[1];
localStorage.setItem('comments_active', commentClass);
});
}
</script>
</div>
<div class="toggle sidebar-toggle">
<span class="toggle-line toggle-line-first"></span>
<span class="toggle-line toggle-line-middle"></span>
<span class="toggle-line toggle-line-last"></span>
</div>
<aside class="sidebar">
<div class="sidebar-inner">
<ul class="sidebar-nav motion-element">
<li class="sidebar-nav-toc">
Table of Contents
</li>
<li class="sidebar-nav-overview">
Overview
</li>
</ul>
<!--noindex-->
<div class="post-toc-wrap sidebar-panel">
</div>
<!--/noindex-->
<div class="site-overview-wrap sidebar-panel">
<div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
<img class="site-author-image" itemprop="image" alt="Tab Zhan"
src="/T-Zhan/images/logo.png">
<p class="site-author-name" itemprop="name">Tab Zhan</p>
<div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
<nav class="site-state">
<div class="site-state-item site-state-posts">
<a href="/T-Zhan/archives/">
<span class="site-state-item-count">3</span>
<span class="site-state-item-name">posts</span>
</a>
</div>
<div class="site-state-item site-state-categories">
<a href="/T-Zhan/categories/">
<span class="site-state-item-count">2</span>
<span class="site-state-item-name">categories</span></a>
</div>
<div class="site-state-item site-state-tags">
<a href="/T-Zhan/tags/">
<span class="site-state-item-count">2</span>
<span class="site-state-item-name">tags</span></a>
</div>
</nav>
</div>
</div>
</div>
</aside>
<div id="sidebar-dimmer"></div>
</div>
</main>
<footer class="footer">
<div class="footer-inner">
<div class="copyright">
©
<span itemprop="copyrightYear">2021</span>
<span class="with-love">
<i class="fa fa-heart"></i>
</span>
<span class="author" itemprop="copyrightHolder">Tab Zhan</span>
</div>
<div class="powered-by">Powered by <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a>
</div>
</div>
</footer>
</div>
<script src="/T-Zhan/lib/anime.min.js"></script>
<script src="/T-Zhan/lib/velocity/velocity.min.js"></script>
<script src="/T-Zhan/lib/velocity/velocity.ui.min.js"></script>
<script src="/T-Zhan/js/utils.js"></script>
<script src="/T-Zhan/js/motion.js"></script>
<script src="/T-Zhan/js/schemes/pisces.js"></script>
<script src="/T-Zhan/js/next-boot.js"></script>
</body>
</html>