cainiaoblog 23.2.171
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CNAME +1 -0
- package/MP_verify_o6dHCK5mIkxNpzvZ.txt +1 -0
- package/README.md +8 -0
- package/about/index.html +54 -0
- package/ads.txt +1 -0
- package/app/manual.html +104 -0
- package/appConfigs/config +1 -0
- package/archives/2018/index.html +48 -0
- package/archives/2019/index.html +48 -0
- package/archives/2019/page/2/index.html +48 -0
- package/archives/2020/index.html +48 -0
- package/archives/2021/index.html +48 -0
- package/archives/2022/index.html +48 -0
- package/archives/2023/index.html +48 -0
- package/archives/index.html +48 -0
- package/archives/page/2/index.html +48 -0
- package/archives/page/3/index.html +48 -0
- package/article/10047.html +148 -0
- package/article/10164.html +64 -0
- package/article/10624.html +436 -0
- package/article/10745.html +586 -0
- package/article/11674.html +71 -0
- package/article/11939.html +72 -0
- package/article/12238.html +86 -0
- package/article/1230.html +533 -0
- package/article/13265.html +69 -0
- package/article/13823.html +78 -0
- package/article/14125.html +72 -0
- package/article/14192.html +561 -0
- package/article/14375.html +85 -0
- package/article/14744.html +83 -0
- package/article/14936.html +451 -0
- package/article/1518.html +250 -0
- package/article/15428.html +71 -0
- package/article/15518.html +288 -0
- package/article/15569.html +418 -0
- package/article/1566.html +122 -0
- package/article/16017.html +156 -0
- package/article/16947.html +440 -0
- package/article/17096.html +82 -0
- package/article/17246.html +89 -0
- package/article/17575.html +350 -0
- package/article/179.html +757 -0
- package/article/18039.html +233 -0
- package/article/18071.html +375 -0
- package/article/18142.html +71 -0
- package/article/19909.html +160 -0
- package/article/20014.html +89 -0
- package/article/20021.html +389 -0
- package/article/20037.html +280 -0
- package/article/20056.html +95 -0
- package/article/20093.html +404 -0
- package/article/2021.html +607 -0
- package/article/20459.html +115 -0
- package/article/20613.html +263 -0
- package/article/20635.html +71 -0
- package/article/21317.html +71 -0
- package/article/21320.html +90 -0
- package/article/21782.html +548 -0
- package/article/22230.html +435 -0
- package/article/22237.html +347 -0
- package/article/22398.html +109 -0
- package/article/22422.html +270 -0
- package/article/22565.html +300 -0
- package/article/23046.html +250 -0
- package/article/23083.html +215 -0
- package/article/23195.html +297 -0
- package/article/23301.html +835 -0
- package/article/23589.html +285 -0
- package/article/23655.html +338 -0
- package/article/23864.html +76 -0
- package/article/23914.html +96 -0
- package/article/24169.html +135 -0
- package/article/24581.html +349 -0
- package/article/2475.html +500 -0
- package/article/24826.html +77 -0
- package/article/24924.html +247 -0
- package/article/25164.html +1495 -0
- package/article/25318.html +394 -0
- package/article/25710.html +1129 -0
- package/article/25734.html +83 -0
- package/article/26083.html +174 -0
- package/article/26147.html +283 -0
- package/article/26291.html +110 -0
- package/article/26354.html +71 -0
- package/article/26624.html +145 -0
- package/article/26639.html +298 -0
- package/article/26850.html +138 -0
- package/article/26940.html +258 -0
- package/article/27796.html +190 -0
- package/article/27800.html +161 -0
- package/article/28963.html +159 -0
- package/article/28976.html +247 -0
- package/article/29042.html +72 -0
- package/article/29596.html +81 -0
- package/article/29619.html +183 -0
- package/article/29623.html +329 -0
- package/article/29829.html +205 -0
- package/article/29abbd1c.html +112 -0
- package/article/30215.html +178 -0
- package/article/30552.html +78 -0
- package/article/30818.html +201 -0
- package/article/31330.html +364 -0
- package/article/3154.html +577 -0
- package/article/31695.html +348 -0
- package/article/31826.html +71 -0
- package/article/31843.html +132 -0
- package/article/32280.html +212 -0
- package/article/32431.html +74 -0
- package/article/32443.html +72 -0
- package/article/32732.html +122 -0
- package/article/3286.html +251 -0
- package/article/32960.html +198 -0
- package/article/33713.html +72 -0
- package/article/33899.html +615 -0
- package/article/34351.html +74 -0
- package/article/34372.html +89 -0
- package/article/34410.html +74 -0
- package/article/34431.html +118 -0
- package/article/3447.html +75 -0
- package/article/34474.html +142 -0
- package/article/34871.html +147 -0
- package/article/35397.html +175 -0
- package/article/3544.html +199 -0
- package/article/35503.html +115 -0
- package/article/35624.html +84 -0
- package/article/35697.html +384 -0
- package/article/35863.html +73 -0
- package/article/36037.html +253 -0
- package/article/36118.html +71 -0
- package/article/3621.html +119 -0
- package/article/36251.html +296 -0
- package/article/36642.html +352 -0
- package/article/37102.html +763 -0
- package/article/37336.html +351 -0
- package/article/37351.html +89 -0
- package/article/3760.html +294 -0
- package/article/37749.html +75 -0
- package/article/37789.html +83 -0
- package/article/38005.html +765 -0
- package/article/38009.html +284 -0
- package/article/38269.html +194 -0
- package/article/38344.html +88 -0
- package/article/38359.html +334 -0
- package/article/38423.html +379 -0
- package/article/38530.html +213 -0
- package/article/38743.html +268 -0
- package/article/38753.html +204 -0
- package/article/38881.html +71 -0
- package/article/39087.html +414 -0
- package/article/39309.html +84 -0
- package/article/39486.html +74 -0
- package/article/39637.html +306 -0
- package/article/39839.html +72 -0
- package/article/39937.html +152 -0
- package/article/39970.html +71 -0
- package/article/402.html +559 -0
- package/article/40698.html +71 -0
- package/article/40811.html +71 -0
- package/article/40964.html +462 -0
- package/article/41011.html +322 -0
- package/article/41152.html +78 -0
- package/article/41696.html +71 -0
- package/article/41717.html +281 -0
- package/article/41777.html +149 -0
- package/article/419.html +985 -0
- package/article/4233.html +136 -0
- package/article/4292.html +86 -0
- package/article/43302.html +96 -0
- package/article/43397.html +106 -0
- package/article/43724.html +281 -0
- package/article/43999.html +224 -0
- package/article/44426.html +77 -0
- package/article/44964.html +137 -0
- package/article/45004.html +123 -0
- package/article/4510.html +83 -0
- package/article/45156.html +320 -0
- package/article/45157.html +52 -0
- package/article/45267.html +87 -0
- package/article/45641.html +207 -0
- package/article/45960.html +75 -0
- package/article/46100.html +1262 -0
- package/article/46366.html +74 -0
- package/article/46771.html +96 -0
- package/article/46911.html +517 -0
- package/article/46948.html +137 -0
- package/article/46ee4850.html +349 -0
- package/article/47019.html +84 -0
- package/article/47532.html +94 -0
- package/article/4783.html +429 -0
- package/article/47972.html +72 -0
- package/article/48216.html +127 -0
- package/article/48252.html +185 -0
- package/article/48520.html +74 -0
- package/article/48722.html +75 -0
- package/article/48807.html +99 -0
- package/article/49126.html +323 -0
- package/article/50001.html +88 -0
- package/article/50058.html +151 -0
- package/article/50343.html +410 -0
- package/article/50510.html +82 -0
- package/article/51082.html +98 -0
- package/article/51677.html +111 -0
- package/article/5204.html +1085 -0
- package/article/52500.html +538 -0
- package/article/52689.html +259 -0
- package/article/52877.html +569 -0
- package/article/53125.html +191 -0
- package/article/53428.html +251 -0
- package/article/53524.html +74 -0
- package/article/53698.html +322 -0
- package/article/53803e6.html +93 -0
- package/article/53924.html +291 -0
- package/article/53962.html +253 -0
- package/article/54006.html +71 -0
- package/article/54018.html +88 -0
- package/article/54161.html +83 -0
- package/article/54178.html +69 -0
- package/article/54258.html +327 -0
- package/article/54295.html +214 -0
- package/article/54313.html +1976 -0
- package/article/54351.html +90 -0
- package/article/54604.html +80 -0
- package/article/54632.html +71 -0
- package/article/54912.html +756 -0
- package/article/54918.html +129 -0
- package/article/55119.html +136 -0
- package/article/55756.html +118 -0
- package/article/55769.html +136 -0
- package/article/55870.html +161 -0
- package/article/56139.html +92 -0
- package/article/56557.html +69 -0
- package/article/56604.html +69 -0
- package/article/56816.html +266 -0
- package/article/56926.html +153 -0
- package/article/57747.html +409 -0
- package/article/57965.html +475 -0
- package/article/58816.html +78 -0
- package/article/59059.html +435 -0
- package/article/59095.html +350 -0
- package/article/59349.html +244 -0
- package/article/59402.html +216 -0
- package/article/59448.html +55 -0
- package/article/59870.html +94 -0
- package/article/59877.html +208 -0
- package/article/5dbb6f41.html +86 -0
- package/article/6008.html +75 -0
- package/article/60327.html +126 -0
- package/article/6035.html +76 -0
- package/article/60428.html +71 -0
- package/article/60544.html +128 -0
- package/article/61319.html +95 -0
- package/article/61367.html +93 -0
- package/article/624d1918.html +292 -0
- package/article/62543.html +71 -0
- package/article/62887.html +169 -0
- package/article/63074.html +120 -0
- package/article/63266.html +311 -0
- package/article/63351.html +74 -0
- package/article/63542.html +104 -0
- package/article/63824.html +275 -0
- package/article/64051.html +653 -0
- package/article/64189b69.html +72 -0
- package/article/64354.html +75 -0
- package/article/64869.html +79 -0
- package/article/64923.html +596 -0
- package/article/65128.html +95 -0
- package/article/65295.html +79 -0
- package/article/6888.html +75 -0
- package/article/7065.html +84 -0
- package/article/7455.html +85 -0
- package/article/7a3ef8f.html +315 -0
- package/article/8140.html +188 -0
- package/article/8190.html +85 -0
- package/article/8225.html +78 -0
- package/article/84c9ccd6.html +159 -0
- package/article/8f9a9ae3.html +82 -0
- package/article/9174.html +73 -0
- package/article/9738.html +294 -0
- package/article/a4145266.html +71 -0
- package/article/bedea419.html +72 -0
- package/article/bf7e7421.html +78 -0
- package/article/c1867fbf.html +103 -0
- package/article/c5576490.html +70 -0
- package/article/dcb0db28.html +76 -0
- package/article/fc3b727a.html +79 -0
- package/atom.xml +445 -0
- package/baidusitemap.xml +1079 -0
- package/blocks/dns.txt +264 -0
- package/blocks/filter.txt +1070 -0
- package/blocks/script.js +42 -0
- package/categories/CDN/index.html +48 -0
- package/categories/IDE/index.html +48 -0
- package/categories/git/index.html +48 -0
- package/categories/hexo/index.html +48 -0
- package/categories//345/205/254/345/205/261/350/212/202/346/227/245/index.html +48 -0
- package/categories//345/210/206/344/272/253/index.html +48 -0
- package/categories//345/211/215/347/253/257/index.html +48 -0
- package/categories//345/211/215/347/253/257/page/2/index.html +48 -0
- package/categories//345/211/215/347/253/257//346/265/217/350/247/210/345/231/250/index.html +48 -0
- package/categories//345/211/215/347/253/257//346/265/217/350/247/210/345/231/250//347/275/221/347/273/234/345/215/217/350/256/256/index.html +48 -0
- package/categories//345/215/232/345/256/242/index.html +48 -0
- package/categories//345/267/245/345/205/267/index.html +48 -0
- package/categories//345/271/277/345/221/212/350/277/207/346/273/244/index.html +48 -0
- package/categories//345/271/277/345/221/212/350/277/207/346/273/244//350/247/206/351/242/221/347/224/265/350/247/206/345/260/217/350/257/264/346/274/253/347/224/273/350/265/204/350/256/257/351/237/263/344/271/220/index.html +48 -0
- package/categories//346/255/243/345/210/231/index.html +48 -0
- package/categories//346/265/217/350/247/210/345/231/250/index.html +48 -0
- package/categories//347/256/227/346/263/225/index.html +48 -0
- package/categories//350/265/204/350/256/257/index.html +48 -0
- package/categories//350/275/273/346/235/276/344/270/200/345/210/273/index.html +48 -0
- package/cdn/css/font-awesome.min.css +4 -0
- package/cdn/css/grids-responsive-min.css +7 -0
- package/cdn/css/normalize.css +349 -0
- package/cdn/css/pure-min.css +11 -0
- package/cdn/fonts/fontawesome-webfont.eot +0 -0
- package/cdn/fonts/fontawesome-webfont.svg +2671 -0
- package/cdn/fonts/fontawesome-webfont.ttf +0 -0
- package/cdn/fonts/fontawesome-webfont.woff +0 -0
- package/cdn/fonts/fontawesome-webfont.woff2 +0 -0
- package/cdn/js/Valine.min.js +17 -0
- package/cdn/js/canvas-nest.js +1 -0
- package/cdn/js/clipboard.min.js +7 -0
- package/cdn/js/crypto-js.js +25 -0
- package/cdn/js/jquery.min.js +2 -0
- package/css/default.css +1144 -0
- package/css/donate.css +338 -0
- package/css/hbe.style.css +749 -0
- package/css/style.css +2095 -0
- package/donate/index.html +39 -0
- package/google917dcf72f6e5c7f5.html +1 -0
- package/guestbook/index.html +68 -0
- package/hosts/ads.txt +149 -0
- package/hosts/flash.txt +9 -0
- package/hosts/github.txt +6 -0
- package/hosts/google.txt +16936 -0
- package/hosts/winrar.txt +2 -0
- package/img/alipay.svg +46 -0
- package/img/bitcoin.svg +135 -0
- package/img/blog.ico +0 -0
- package/img/blog.png +0 -0
- package/img/gaba.png +0 -0
- package/img/github.svg +1 -0
- package/img/like.svg +1 -0
- package/img/mp-mini.jpg +0 -0
- package/img/mp.png +0 -0
- package/img/paypal.svg +63 -0
- package/img/upy_logo.svg +59 -0
- package/img/wechat.svg +49 -0
- package/index.html +48 -0
- package/jd_root.txt +1 -0
- package/js/codeblock-resizer.js +51 -0
- package/js/dark.js +12 -0
- package/js/donate.js +87 -0
- package/js/fixedPage.js +106 -0
- package/js/gitment.browser.js +3751 -0
- package/js/search.js +86 -0
- package/js/share.js +60 -0
- package/js/smartresize.js +32 -0
- package/js/totop.js +12 -0
- package/kankan/index.html +77 -0
- package/lib/hbe.js +293 -0
- package/package.json +25 -0
- package/page/10/index.html +49 -0
- package/page/11/index.html +59 -0
- package/page/12/index.html +67 -0
- package/page/13/index.html +63 -0
- package/page/14/index.html +66 -0
- package/page/15/index.html +60 -0
- package/page/16/index.html +60 -0
- package/page/17/index.html +62 -0
- package/page/18/index.html +61 -0
- package/page/19/index.html +58 -0
- package/page/2/index.html +48 -0
- package/page/20/index.html +57 -0
- package/page/21/index.html +61 -0
- package/page/22/index.html +55 -0
- package/page/23/index.html +64 -0
- package/page/24/index.html +60 -0
- package/page/25/index.html +58 -0
- package/page/26/index.html +48 -0
- package/page/27/index.html +58 -0
- package/page/3/index.html +48 -0
- package/page/4/index.html +48 -0
- package/page/5/index.html +51 -0
- package/page/6/index.html +51 -0
- package/page/7/index.html +51 -0
- package/page/8/index.html +53 -0
- package/page/9/index.html +48 -0
- package/randomcall/README.html +1 -0
- package/randomcall/lucker.html +290 -0
- package/randomcall/lucky.png +0 -0
- package/robots.txt +22 -0
- package/search.xml +6740 -0
- package/sitemap.xml +2669 -0
- package/tags//345/216/237/345/210/233/index.html +48 -0
- package/tags//345/250/261/344/271/220/index.html +48 -0
- package/tags//346/211/213/345/206/231/index.html +48 -0
- package/tags//347/226/253/346/203/205/index.html +48 -0
- package/tags//350/275/254/350/275/275/index.html +48 -0
- package/tags//350/275/254/350/275/275/page/2/index.html +48 -0
- package/v.html +90 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="zh-CN" data-dark><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"><meta content="yes" name="apple-mobile-web-app-capable"><meta content="black-translucent" name="apple-mobile-web-app-status-bar-style"><meta content="telephone=no" name="format-detection"><meta name="description" content="前端壹菜鸟,记录工作难题,关注前端知识,收集精彩博文,做技术的搬运工"><meta name="msvalidate.01" content="0FE4D8B3381D3D87088996B886E1E2BD"><title>浅谈React性能优化的方向 | 前端壹菜鸟</title><link rel="stylesheet" type="text/css" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/css/style.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/normalize.css@latest/normalize.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/purecss@latest/build/pure-min.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/purecss@latest/build/grids-responsive-min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css"><link rel="icon" mask="" sizes="any" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.ico"><link rel="Shortcut Icon" type="image/x-icon" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.ico"><link rel="apple-touch-icon" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.png"><link rel="apple-touch-icon-precomposed" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.png"><link rel="alternate" type="application/atom+xml" href="/atom.xml"><script type="text/javascript" src="//cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8385136408348258"></script><script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script><script>(function(){
|
|
2
|
+
var bp = document.createElement('script');
|
|
3
|
+
var curProtocol = window.location.protocol.split(':')[0];
|
|
4
|
+
if (curProtocol === 'https'){
|
|
5
|
+
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
|
|
6
|
+
}
|
|
7
|
+
else{
|
|
8
|
+
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
|
|
9
|
+
}
|
|
10
|
+
var s = document.getElementsByTagName("script")[0];
|
|
11
|
+
s.parentNode.insertBefore(bp, s);
|
|
12
|
+
})();
|
|
13
|
+
</script><script>(function(){
|
|
14
|
+
var src = 'https://jspassport.ssl.qhimg.com/11.0.1.js?d182b3f28525f2db83acfaaf6e696dba';
|
|
15
|
+
document.write('<script src="' + src + '" id="sozz"><\/script>');
|
|
16
|
+
})();
|
|
17
|
+
</script><script>var _hmt=_hmt||[];(function(){var hm=document.createElement("script");hm.src='https://hm.baidu.com/hm.js?011f0b44e8452bfa57fbfa23c5fe7683';var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm, s);})();
|
|
18
|
+
</script><script async src="https://www.googletagmanager.com/gtag/js?id=UA-150860401-1"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);};gtag('js',new Date());gtag('config','UA-150860401-1');
|
|
19
|
+
</script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/fixedPage.min.js"></script><meta name="generator" content="Hexo 6.3.0"></head><body><div class="body_container"><div id="header"><div class="site-name"><a id="logo" href="/.">前端壹菜鸟</a><p class="description">关注前端知识,收集精彩博文,做技术的搬运工</p></div><div id="nav-menu"><a class="current" href="/." target="_self"><i class="fa fa-home"> 首页</i></a><a href="/archives/" target="_self"><i class="fa fa-archive"> 归档</i></a><a href="/guestbook/" target="_self"><i class="fa fa-comments"> 留言</i></a><a href="/about/" target="_self"><i class="fa fa-user"> 关于</i></a><a href="https://laonongmin.online/" target="_target"><i class="fa fa-group"> 看看</i></a><a href="https://love.xuehuayu.cn/" target="_target"><i class="fa fa-heart"> LOVE</i></a></div></div><div class="pure-g" id="layout"><div class="pure-u-1 pure-u-md-3-4"><div class="content_container"><div class="post"><h1 class="post-title c-post">浅谈React性能优化的方向</h1><div class="post-meta"><span class="date">2019-11-21</span><span> | </span><span class="tag"><a href="/tags/%E8%BD%AC%E8%BD%BD/">转载 </a></span><span> | </span><span class="category"><a href="/categories/%E5%89%8D%E7%AB%AF/">前端 </a></span><span id="busuanzi_container_page_pv"> | <span id="busuanzi_value_page_pv"><i class="fa fa-spinner"></i></span><span> 阅读</span></span><span class="post-time"><span class="post-meta-item-text"> | </span><span class="post-meta-item-icon"><i class="fa fa-keyboard-o"></i><span class="post-count"> 4.2k</span><span class="post-meta-item-text"> 字</span></span></span><span class="post-time"> | <span class="post-meta-item-icon"><i class="fa fa-hourglass-half"></i><span class="post-count"> 17</span><span class="post-meta-item-text"> 分钟</span></span></span></div><a class="disqus-comment-count" href="/article/50343.html#vcomment"><span class="waline-comment-count" data-path="/article/50343.html"></span><span> 条评论</span></a><div class="post-content"><p><code>原文地址:https://juejin.im/post/5d045350f265da1b695d5bf2#heading-0</code></p>
|
|
20
|
+
<p>React 渲染性能优化的三个方向,其实也适用于其他软件开发领域,这三个方向分别是:</p>
|
|
21
|
+
<ul>
|
|
22
|
+
<li><strong>减少计算的量</strong>。 -> 对应到 React 中就是<strong>减少渲染的节点 或者 降低组件渲染的复杂度</strong></li>
|
|
23
|
+
<li><strong>利用缓存</strong>。-> 对应到 React 中就是<strong>如何避免重新渲染,利用函数式编程的 memo 方式来避免组件重新渲染</strong></li>
|
|
24
|
+
<li><strong>精确重新计算的范围</strong>。 对应到 React 中就是<strong>绑定组件和状态关系, 精确判断更新的’时机’和’范围’. 只重新渲染’脏’的组件,或者说降低渲染范围</strong><span id="more"></span></li>
|
|
25
|
+
</ul>
|
|
26
|
+
<p><strong>目录</strong></p>
|
|
27
|
+
<ul>
|
|
28
|
+
<li><p><a href="#%E5%87%8F%E5%B0%91%E6%B8%B2%E6%9F%93%E7%9A%84%E8%8A%82%E7%82%B9%E9%99%8D%E4%BD%8E%E6%B8%B2%E6%9F%93%E8%AE%A1%E7%AE%97%E9%87%8F%E5%A4%8D%E6%9D%82%E5%BA%A6">减少渲染的节点/降低渲染计算量(复杂度)</a></p>
|
|
29
|
+
</li>
|
|
30
|
+
<li><p><a href="#0%EF%B8%8F%E2%83%A3-%E4%B8%8D%E8%A6%81%E5%9C%A8%E6%B8%B2%E6%9F%93%E5%87%BD%E6%95%B0%E9%83%BD%E8%BF%9B%E8%A1%8C%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84%E8%AE%A1%E7%AE%97">0️⃣ 不要在渲染函数都进行不必要的计算</a></p>
|
|
31
|
+
</li>
|
|
32
|
+
<li><p><a href="#1%EF%B8%8F%E2%83%A3-%E5%87%8F%E5%B0%91%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84%E5%B5%8C%E5%A5%97">1️⃣ 减少不必要的嵌套</a></p>
|
|
33
|
+
</li>
|
|
34
|
+
<li><p><a href="#2%EF%B8%8F%E2%83%A3-%E8%99%9A%E6%8B%9F%E5%88%97%E8%A1%A8">2️⃣ 虚拟列表</a></p>
|
|
35
|
+
</li>
|
|
36
|
+
<li><p><a href="#3%EF%B8%8F%E2%83%A3-%E6%83%B0%E6%80%A7%E6%B8%B2%E6%9F%93">3️⃣ 惰性渲染</a></p>
|
|
37
|
+
</li>
|
|
38
|
+
<li><p><a href="#4%EF%B8%8F%E2%83%A3-%E9%80%89%E6%8B%A9%E5%90%88%E9%80%82%E7%9A%84%E6%A0%B7%E5%BC%8F%E6%96%B9%E6%A1%88">4️⃣ 选择合适的样式方案</a></p>
|
|
39
|
+
</li>
|
|
40
|
+
<li><p><a href="#%E9%81%BF%E5%85%8D%E9%87%8D%E6%96%B0%E6%B8%B2%E6%9F%93">避免重新渲染</a></p>
|
|
41
|
+
</li>
|
|
42
|
+
<li><p><a href="#0%EF%B8%8F%E2%83%A3-%E7%AE%80%E5%8C%96-props">0️⃣ 简化 props</a></p>
|
|
43
|
+
</li>
|
|
44
|
+
<li><p><a href="#1%EF%B8%8F%E2%83%A3-%E4%B8%8D%E5%8F%98%E7%9A%84%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%E5%99%A8">1️⃣ 不变的事件处理器</a></p>
|
|
45
|
+
</li>
|
|
46
|
+
<li><p><a href="#2%EF%B8%8F%E2%83%A3-%E4%B8%8D%E5%8F%AF%E5%8F%98%E6%95%B0%E6%8D%AE">2️⃣ 不可变数据</a></p>
|
|
47
|
+
</li>
|
|
48
|
+
<li><p><a href="#3%EF%B8%8F%E2%83%A3-%E7%AE%80%E5%8C%96-state">3️⃣ 简化 state</a></p>
|
|
49
|
+
</li>
|
|
50
|
+
<li><p><a href="#4%EF%B8%8F%E2%83%A3-%E4%BD%BF%E7%94%A8-recompose-%E7%B2%BE%E7%BB%86%E5%8C%96%E6%AF%94%E5%AF%B9">4️⃣ 使用 recompose 精细化比对</a></p>
|
|
51
|
+
</li>
|
|
52
|
+
<li><p><a href="#%E7%B2%BE%E7%BB%86%E5%8C%96%E6%B8%B2%E6%9F%93">精细化渲染</a></p>
|
|
53
|
+
</li>
|
|
54
|
+
<li><p><a href="#0%EF%B8%8F%E2%83%A3-%E5%93%8D%E5%BA%94%E5%BC%8F%E6%95%B0%E6%8D%AE%E7%9A%84%E7%B2%BE%E7%BB%86%E5%8C%96%E6%B8%B2%E6%9F%93">0️⃣ 响应式数据的精细化渲染</a></p>
|
|
55
|
+
</li>
|
|
56
|
+
<li><p><a href="#1%EF%B8%8F%E2%83%A3-%E4%B8%8D%E8%A6%81%E6%BB%A5%E7%94%A8-context">1️⃣ 不要滥用 Context</a></p>
|
|
57
|
+
</li>
|
|
58
|
+
<li><p><a href="#%E6%89%A9%E5%B1%95">扩展</a></p>
|
|
59
|
+
</li>
|
|
60
|
+
</ul>
|
|
61
|
+
<h2 id="减少渲染的节点-x2F-降低渲染计算量-复杂度"><a href="#减少渲染的节点-x2F-降低渲染计算量-复杂度" class="headerlink" title="减少渲染的节点/降低渲染计算量(复杂度)"></a>减少渲染的节点/降低渲染计算量(复杂度)</h2><p>首先从计算的量上下功夫,减少节点渲染的数量或者降低渲染的计算量可以显著的提高组件渲染性能。</p>
|
|
62
|
+
<h3 id="0️⃣-不要在渲染函数都进行不必要的计算"><a href="#0️⃣-不要在渲染函数都进行不必要的计算" class="headerlink" title="0️⃣ 不要在渲染函数都进行不必要的计算"></a>0️⃣ 不要在渲染函数都进行不必要的计算</h3><p>比如不要在渲染函数(render)中进行数组排序、数据转换、订阅事件、创建事件处理器等等. <strong>渲染函数中不应该放置太多副作用</strong></p>
|
|
63
|
+
<h3 id="1️⃣-减少不必要的嵌套"><a href="#1️⃣-减少不必要的嵌套" class="headerlink" title="1️⃣ 减少不必要的嵌套"></a>1️⃣ 减少不必要的嵌套</h3><p><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e532d863b10?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><br>我们团队是重度的 <code>styled-components</code> 用户,<strong>其实大部分情况下我们都不需要这个玩意</strong>,比如纯静态的样式规则,以及需要重度性能优化的场景。除了性能问题,另外一个困扰我们的是它带来的节点嵌套地狱(如上图)。</p>
|
|
64
|
+
<p>所以我们需要理性地选择一些工具,比如使用原生的 CSS,减少 React 运行时的负担.</p>
|
|
65
|
+
<p><strong>一般不必要的节点嵌套都是滥用高阶组件/RenderProps 导致的。所以还是那句话‘只有在必要时才使用 xxx’</strong>。 有很多种方式来代替高阶组件/RenderProps,例如优先使用 props、React Hooks</p>
|
|
66
|
+
<h3 id="2️⃣-虚拟列表"><a href="#2️⃣-虚拟列表" class="headerlink" title="2️⃣ 虚拟列表"></a>2️⃣ 虚拟列表</h3><p>虚拟列表是常见的‘长列表’和’复杂组件树’优化方式,它优化的本质就是减少渲染的节点。</p>
|
|
67
|
+
<p>虚拟列表只渲染当前视口可见元素:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e532e72f064?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><br>虚拟列表渲染性能对比:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e532ca493d0?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><br>虚拟列表常用于以下组件场景:</p>
|
|
68
|
+
<ul>
|
|
69
|
+
<li>无限滚动列表,grid, 表格,下拉列表,spreadsheets</li>
|
|
70
|
+
<li>无限切换的日历或轮播图</li>
|
|
71
|
+
<li>大数据量或无限嵌套的树</li>
|
|
72
|
+
<li>聊天窗,数据流(feed), 时间轴</li>
|
|
73
|
+
<li>等等</li>
|
|
74
|
+
</ul>
|
|
75
|
+
<p>相关组件方案:</p>
|
|
76
|
+
<ul>
|
|
77
|
+
<li><a target="_blank" rel="noopener" href="https://github.com/bvaughn/react-virtualized">react-virtualized</a></li>
|
|
78
|
+
<li><a target="_blank" rel="noopener" href="https://github.com/bvaughn/react-window">react-window</a> 更轻量的 react-virtualized, 同出一个作者</li>
|
|
79
|
+
<li><a target="_blank" rel="noopener" href="https://github.com/bvaughn/react-virtualized#friends">更多</a></li>
|
|
80
|
+
</ul>
|
|
81
|
+
<p>扩展:</p>
|
|
82
|
+
<ul>
|
|
83
|
+
<li><a target="_blank" rel="noopener" href="https://bvaughn.github.io/forward-js-2017/#/0/0">Creating more efficient React views with windowing</a></li>
|
|
84
|
+
<li><a target="_blank" rel="noopener" href="https://addyosmani.com/blog/react-window/">Rendering large lists with react-window</a></li>
|
|
85
|
+
</ul>
|
|
86
|
+
<h3 id="3️⃣-惰性渲染"><a href="#3️⃣-惰性渲染" class="headerlink" title="3️⃣ 惰性渲染"></a>3️⃣ 惰性渲染</h3><p><strong>惰性渲染的初衷本质上和虚表一样,也就是说我们只在必要时才去渲染对应的节点</strong>。</p>
|
|
87
|
+
<p>举个典型的例子,我们常用 Tab 组件,我们没有必要一开始就将所有 Tab 的 panel 都渲染出来,而是等到该 Tab 被激活时才去惰性渲染。</p>
|
|
88
|
+
<p>还有很多场景会用到惰性渲染,例如树形选择器,模态弹窗,下拉列表,折叠组件等等。</p>
|
|
89
|
+
<p>这里就不举具体的代码例子了,留给读者去思考.</p>
|
|
90
|
+
<h3 id="4️⃣-选择合适的样式方案"><a href="#4️⃣-选择合适的样式方案" class="headerlink" title="4️⃣ 选择合适的样式方案"></a>4️⃣ 选择合适的样式方案</h3><p><img src="https://user-gold-cdn.xitu.io/2019/6/16/16b5dd10a46eceb2?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><br>如图(图片来源于<a target="_blank" rel="noopener" href="https://blog.primehammer.com/the-performance-of-styled-react-components/">THE PERFORMANCE OF STYLED REACT COMPONENTS</a>), 这个图片是17年的了,但是大抵的趋势还是这样。</p>
|
|
91
|
+
<p>所以在样式运行时性能方面大概可以总结为:<code>CSS > 大部分CSS-in-js > inline style</code></p>
|
|
92
|
+
<hr>
|
|
93
|
+
<h2 id="避免重新渲染"><a href="#避免重新渲染" class="headerlink" title="避免重新渲染"></a>避免重新渲染</h2><p>减少不必要的重新渲染也是 React 组件性能优化的重要方向. 为了避免不必要的组件重新渲染需要在做到两点:</p>
|
|
94
|
+
<ol>
|
|
95
|
+
<li>保证组件纯粹性。即控制组件的副作用,如果组件有副作用则无法安全地缓存渲染结果</li>
|
|
96
|
+
<li>通过<code>shouldComponentUpdate</code>生命周期函数来比对 state 和 props, 确定是否要重新渲染。对于函数组件可以使用<code>React.memo</code>包装</li>
|
|
97
|
+
</ol>
|
|
98
|
+
<p>另外这些措施也可以帮助你更容易地优化组件重新渲染:</p>
|
|
99
|
+
<h3 id="0️⃣-简化-props"><a href="#0️⃣-简化-props" class="headerlink" title="0️⃣ 简化 props"></a>0️⃣ 简化 props</h3><p><strong>① 如果一个组件的 props 太复杂一般意味着这个组件已经违背了‘单一职责’,首先应该尝试对组件进行拆解</strong>.<br><strong>② 另外复杂的 props 也会变得难以维护, 比如会影响<code>shallowCompare</code>效率, 还会让组件的变动变得难以预测和调试</strong>.</p>
|
|
100
|
+
<p>下面是一个典型的例子, 为了判断列表项是否处于激活状态,这里传入了一个当前激活的 id:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e53250b584f?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><br>这是一个非常糟糕的设计,一旦激活 id 变动,所有列表项都会重新刷新. 更好的解决办法是使用类似<code>actived</code>这样的布尔值 prop. actived 现在只有两种变动情况,也就是说激活 id 的变动,最多只有两个组件需要重新渲染.</p>
|
|
101
|
+
<p><strong>简化的 props 更容易理解, 且可以提高组件缓存的命中率</strong></p>
|
|
102
|
+
<h3 id="1️⃣-不变的事件处理器"><a href="#1️⃣-不变的事件处理器" class="headerlink" title="1️⃣ 不变的事件处理器"></a>1️⃣ 不变的事件处理器</h3><p>①<strong>避免使用箭头函数形式的事件处理器</strong>, 例如:</p>
|
|
103
|
+
<pre><code><ComplexComponent onClick={evt => onClick(evt.id)} otherProps={values} />
|
|
104
|
+
复制代码
|
|
105
|
+
</code></pre>
|
|
106
|
+
<p>假设 ComplexComponent 是一个复杂的 PureComponent, 这里使用箭头函数,其实每次渲染时都会创建一个新的事件处理器,这会导致 ComplexComponent 始终会被重新渲染.</p>
|
|
107
|
+
<p>更好的方式是使用实例方法:</p>
|
|
108
|
+
<pre><code>classMyComponentextendsComponent{
|
|
109
|
+
render() {
|
|
110
|
+
<ComplexComponent onClick={this.handleClick} otherProps={values} />;
|
|
111
|
+
}
|
|
112
|
+
handleClick = () => {
|
|
113
|
+
/*...*/
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
复制代码
|
|
117
|
+
</code></pre>
|
|
118
|
+
<p>② 即使现在使用<code>hooks</code>,我依然会<strong>使用<code>useCallback</code>来包装事件处理器</strong>,尽量给下级组件暴露一个静态的函数:</p>
|
|
119
|
+
<pre><code>const handleClick = useCallback(() => {
|
|
120
|
+
/*...*/
|
|
121
|
+
}, []);
|
|
122
|
+
|
|
123
|
+
return<ComplexComponentonClick={handleClick}otherProps={values} />;
|
|
124
|
+
复制代码
|
|
125
|
+
</code></pre>
|
|
126
|
+
<p>但是如果<code>useCallback</code>依赖于很多状态,你的<code>useCallback</code>可能会变成这样:</p>
|
|
127
|
+
<pre><code>const handleClick = useCallback(() => {
|
|
128
|
+
/*...*/// 🤭
|
|
129
|
+
}, [foo, bar, baz, bazz, bazzzz]);
|
|
130
|
+
复制代码
|
|
131
|
+
</code></pre>
|
|
132
|
+
<p>这种写法实在让人难以接受,这时候谁还管什么函数式非函数式的。我是这样处理的:</p>
|
|
133
|
+
<pre><code>functionuseRefProps<T>(props: T) {
|
|
134
|
+
const ref = useRef < T > props;
|
|
135
|
+
// 每次渲染更新props
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
ref.current = props;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
functionMyComp(props) {
|
|
142
|
+
const propsRef = useRefProps(props);
|
|
143
|
+
|
|
144
|
+
// 现在handleClick是始终不变的const handleClick = useCallback(() => {
|
|
145
|
+
const { foo, bar, baz, bazz, bazzzz } = propsRef.current;
|
|
146
|
+
// do something
|
|
147
|
+
}, []);
|
|
148
|
+
}
|
|
149
|
+
复制代码
|
|
150
|
+
</code></pre>
|
|
151
|
+
<p>③<strong>设计更方便处理的 Event Props</strong>. 有时候我们会被逼的不得不使用箭头函数来作为事件处理器:</p>
|
|
152
|
+
<pre><code><List>
|
|
153
|
+
{list.map(i => (
|
|
154
|
+
<Itemkey={i.id}onClick={() => handleDelete(i.id)} value={i.value} />
|
|
155
|
+
))}
|
|
156
|
+
</List>复制代码
|
|
157
|
+
</code></pre>
|
|
158
|
+
<p>上面的 onClick 是一个糟糕的实现,它没有携带任何信息来标识事件来源,所以这里只能使用闭包形式,更好的设计可能是这样的:</p>
|
|
159
|
+
<pre><code>// onClick传递事件来源信息const handleDelete = useCallback((id: string) => {
|
|
160
|
+
/*删除操作*/
|
|
161
|
+
}, []);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<List>
|
|
165
|
+
{list.map(i => (
|
|
166
|
+
<Itemkey={i.id}id={i.id}onClick={handleDelete}value={i.value} />
|
|
167
|
+
))}
|
|
168
|
+
</List>
|
|
169
|
+
);
|
|
170
|
+
复制代码
|
|
171
|
+
</code></pre>
|
|
172
|
+
<p>如果是第三方组件或者 DOM 组件呢? 实在不行,看能不能传递<code>data-*</code>属性:</p>
|
|
173
|
+
<pre><code>const handleDelete = useCallback(event => {
|
|
174
|
+
const id = event.currentTarget.dataset.id;
|
|
175
|
+
/*删除操作*/
|
|
176
|
+
}, []);
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<ul>
|
|
180
|
+
{list.map(i => (
|
|
181
|
+
<likey={i.id}data-id={i.id}onClick={handleDelete}value={i.value} />
|
|
182
|
+
))}
|
|
183
|
+
</ul>
|
|
184
|
+
);
|
|
185
|
+
复制代码
|
|
186
|
+
</code></pre>
|
|
187
|
+
<h3 id="2️⃣-不可变数据"><a href="#2️⃣-不可变数据" class="headerlink" title="2️⃣ 不可变数据"></a>2️⃣ 不可变数据</h3><p>不可变数据可以让状态变得可预测,也让 shouldComponentUpdate ‘浅比较’变得更可靠和高效. 笔者在<a target="_blank" rel="noopener" href="https://juejin.im/post/5cdc2f54e51d453b0c35930d#heading-8">React 组件设计实践总结 04 - 组件的思维</a>介绍过不可变数据,有兴趣读者可以看看.</p>
|
|
188
|
+
<p>相关的工具有<a target="_blank" rel="noopener" href="https://github.com/facebook/immutable-js">Immutable.js</a>、<a target="_blank" rel="noopener" href="https://github.com/mweststrate/immer">Immer</a>、immutability-helper 以及 seamless-immutable。</p>
|
|
189
|
+
<h3 id="3️⃣-简化-state"><a href="#3️⃣-简化-state" class="headerlink" title="3️⃣ 简化 state"></a>3️⃣ 简化 state</h3><p><strong>不是所有状态都应该放在组件的 state 中</strong>. 例如缓存数据。按照我的原则是:<strong>如果需要组件响应它的变动, 或者需要渲染到视图中的数据才应该放到 state 中。这样可以避免不必要的数据变动导致组件重新渲染.</strong></p>
|
|
190
|
+
<h3 id="4️⃣-使用-recompose-精细化比对"><a href="#4️⃣-使用-recompose-精细化比对" class="headerlink" title="4️⃣ 使用 recompose 精细化比对"></a>4️⃣ 使用 recompose 精细化比对</h3><p>尽管 hooks 出来后,recompose 宣称不再更新了,但还是不影响我们使用 recompose 来控制<code>shouldComponentUpdate</code>方法, 比如它提供了以下方法来精细控制应该比较哪些 props:</p>
|
|
191
|
+
<pre><code>/* 相当于React.memo */
|
|
192
|
+
pure()
|
|
193
|
+
/* 自定义比较 */
|
|
194
|
+
shouldUpdate(test: (props: Object, nextProps: Object) =>boolean): HigherOrderComponent
|
|
195
|
+
/* 只比较指定key */
|
|
196
|
+
onlyUpdateForKeys( propKeys: Array<string>): HigherOrderComponent
|
|
197
|
+
复制代码
|
|
198
|
+
</code></pre>
|
|
199
|
+
<p>其实还可以再扩展一下,比如<code>omitUpdateForKeys</code>忽略比对某些 key.</p>
|
|
200
|
+
<h2 id="精细化渲染"><a href="#精细化渲染" class="headerlink" title="精细化渲染"></a>精细化渲染</h2><p>所谓精细化渲染指的是<strong>只有一个数据来源导致组件重新渲染</strong>, 比如说 A 只依赖于 a 数据,那么只有在 a 数据变动时才渲染 A, 其他状态变化不应该影响组件 A。</p>
|
|
201
|
+
<p>Vue 和 Mobx 宣称自己性能好的一部分原因是它们的’响应式系统’, <strong>它允许我们定义一些‘响应式数据’,当这些响应数据变动时,依赖这些响应式数据视图就会重新渲染</strong>. 来看看 Vue 官方是如何描述的:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e532d4abd3c?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"></p>
|
|
202
|
+
<h3 id="0️⃣-响应式数据的精细化渲染"><a href="#0️⃣-响应式数据的精细化渲染" class="headerlink" title="0️⃣ 响应式数据的精细化渲染"></a>0️⃣ 响应式数据的精细化渲染</h3><p><strong>大部分情况下,响应式数据可以实现视图精细化的渲染, 但它还是不能避免开发者写出低效的程序</strong>. <strong>本质上还是因为组件违背‘单一职责’</strong>.</p>
|
|
203
|
+
<p>举个例子,现在有一个 MyComponent 组件,依赖于 A、B、C 三个数据源,来构建一个 vdom 树。现在的问题是什么呢?现在只要 A、B、C 任意一个变动,那么 MyComponent 整个就会重新渲染:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e532546f6d6?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><br>更好的做法是让组件的职责更单一,精细化地依赖响应式数据,或者说对响应式数据进行‘隔离’. 如下图, A、B、C 都抽取各自的组件中了,现在 A 变动只会渲染 A 组件本身,而不会影响父组件和 B、C 组件:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e53ae748821?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"></p>
|
|
204
|
+
<p>举一个典型的例子,列表渲染:</p>
|
|
205
|
+
<pre><code>import React from'react';
|
|
206
|
+
import { observable } from'mobx';
|
|
207
|
+
import { observer } from'mobx-react-lite';
|
|
208
|
+
|
|
209
|
+
const initialList = [];
|
|
210
|
+
for (let i = 0; i < 10; i++) {
|
|
211
|
+
initialList.push({ id: i, name: `name-${i}`, value: 0 });
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const store = observable({
|
|
215
|
+
list: initialList,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
exportconst List = observer(() => {
|
|
219
|
+
const list = store.list;
|
|
220
|
+
console.log('List渲染');
|
|
221
|
+
return (
|
|
222
|
+
<divclassName="list-container"><ul>
|
|
223
|
+
{list.map((i, idx) => (
|
|
224
|
+
<divclassName="list-item"key={i.id}>
|
|
225
|
+
{/* 假设这是一个复杂的组件 */}
|
|
226
|
+
{console.log('render', i.id)}
|
|
227
|
+
<spanclassName="list-item-name">{i.name} </span><spanclassName="list-item-value">{i.value} </span><buttonclassName="list-item-increment"onClick={() => {
|
|
228
|
+
i.value++;
|
|
229
|
+
console.log('递增');
|
|
230
|
+
} }
|
|
231
|
+
>
|
|
232
|
+
递增
|
|
233
|
+
</button><buttonclassName="list-item-increment"onClick={() => {
|
|
234
|
+
if (idx < list.length-1) {
|
|
235
|
+
console.log('移位');
|
|
236
|
+
lett = list[idx];list[idx] = list[idx + 1];
|
|
237
|
+
list[idx + 1] = t;
|
|
238
|
+
}
|
|
239
|
+
} }
|
|
240
|
+
>
|
|
241
|
+
下移
|
|
242
|
+
</button></div>
|
|
243
|
+
))}
|
|
244
|
+
</ul></div>
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
复制代码
|
|
248
|
+
</code></pre>
|
|
249
|
+
<p>上述的例子是存在性能问题的,单个 list-item 的递增和移位都会导致整个列表的重新渲染:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e53c9978c97?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><br>原因大概能猜出来吧? 对于 Vue 或者 Mobx 来说,<strong>一个组件的渲染函数就是一个依赖收集的上下文</strong>。上面 List 组件渲染函数内’访问’了所有的列表项数据,那么 Vue 或 Mobx 就会认为你这个组件依赖于所有的列表项,这样就导致,只要任意一个列表项的属性值变动就会重新渲染整个 List 组件。</p>
|
|
250
|
+
<p>解决办法也很简单,就是将数据隔离抽取到单一职责的组件中。<strong>对于 Vue 或 Mobx 来说,越细粒度的组件,可以收获更高的性能优化效果</strong>:</p>
|
|
251
|
+
<pre><code>exportconst ListItem = observer(props => {
|
|
252
|
+
const { item, onShiftDown } = props;
|
|
253
|
+
return (
|
|
254
|
+
<divclassName="list-item">
|
|
255
|
+
{console.log('render', item.id)}
|
|
256
|
+
{/* 假设这是一个复杂的组件 */}
|
|
257
|
+
<spanclassName="list-item-name">{item.name} </span><spanclassName="list-item-value">{item.value} </span><buttonclassName="list-item-increment"onClick={() => {
|
|
258
|
+
item.value++;
|
|
259
|
+
console.log('递增');
|
|
260
|
+
} }
|
|
261
|
+
>
|
|
262
|
+
递增
|
|
263
|
+
</button><buttonclassName="list-item-increment"onClick={() => onShiftDown(item)}>
|
|
264
|
+
下移
|
|
265
|
+
</button></div>
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
exportconst List = observer(() => {
|
|
270
|
+
const list = store.list;
|
|
271
|
+
const handleShiftDown = useCallback(item => {
|
|
272
|
+
const idx = list.findIndex(i => i.id === item.id);
|
|
273
|
+
if (idx !== -1 && idx < list.length - 1) {
|
|
274
|
+
console.log('移位');
|
|
275
|
+
let t = list[idx];
|
|
276
|
+
list[idx] = list[idx + 1];
|
|
277
|
+
list[idx + 1] = t;
|
|
278
|
+
}
|
|
279
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
280
|
+
}, []);
|
|
281
|
+
|
|
282
|
+
console.log('List 渲染');
|
|
283
|
+
|
|
284
|
+
return (
|
|
285
|
+
<divclassName="list-container"><ul>
|
|
286
|
+
{list.map((i, idx) => (
|
|
287
|
+
<ListItemkey={i.id}item={i}onShiftDown={handleShiftDown} />
|
|
288
|
+
))}
|
|
289
|
+
</ul></div>
|
|
290
|
+
);
|
|
291
|
+
});
|
|
292
|
+
复制代码
|
|
293
|
+
</code></pre>
|
|
294
|
+
<p>效果很明显, list-item 递增只会重新渲染本身; 而移位只会重新渲染 List, 因为列表项没有变动, 所以下级 list-item 也不需要重新渲染:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e53aea289bf?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"></p>
|
|
295
|
+
<h3 id="1️⃣-不要滥用-Context"><a href="#1️⃣-不要滥用-Context" class="headerlink" title="1️⃣ 不要滥用 Context"></a>1️⃣ 不要滥用 Context</h3><p><strong>其实 Context 的用法和响应式数据正好相反</strong>。笔者也看过不少滥用 Context API 的例子, 说到底还是没有处理好‘状态的作用域问题’.</p>
|
|
296
|
+
<p>首先要理解 Context API 的更新特点,<strong>它是可以穿透<code>React.memo</code>或者<code>shouldComponentUpdate</code>的比对的,也就是说,一旦 Context 的 Value 变动,所有依赖该 Context 的组件会全部 forceUpdate</strong>.</p>
|
|
297
|
+
<p><strong>这个和 Mobx 和 Vue 的响应式系统不同,Context API 并不能细粒度地检测哪些组件依赖哪些状态,所以说上节提到的‘精细化渲染’组件模式,在 Context 这里就成为了‘反模式’</strong>.</p>
|
|
298
|
+
<p>总结一下使用 Context API 要遵循一下原则:</p>
|
|
299
|
+
<ul>
|
|
300
|
+
<li><strong>明确状态作用域, Context 只放置必要的,关键的,被大多数组件所共享的状态</strong>。比较典型的是鉴权状态</li>
|
|
301
|
+
</ul>
|
|
302
|
+
<p>举一个简单的例子:<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e53c17cd5e1?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e53c9bdc0b3?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"><br>扩展:Context其实有个实验性或者说非公开的选项<code>observedBits</code>, 可以用于控制ContextConsumer是否需要更新. 详细可以看这篇文章<<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/51073183">ObservedBits: React Context的秘密功能</a>>. 不过不推荐在实际项目中使用,而且这个API也比较难用,不如直接上mobx。</p>
|
|
303
|
+
<ul>
|
|
304
|
+
<li><strong>粗粒度地订阅 Context</strong></li>
|
|
305
|
+
</ul>
|
|
306
|
+
<p>如下图. 细粒度的 Context 订阅会导致不必要的重新渲染, 所以这里推荐粗粒度的订阅. 比如在父级订阅 Context,然后再通过 props 传递给下级。<br><img src="https://user-gold-cdn.xitu.io/2019/6/15/16b58e53c08a377e?imageView2/0/w/1280/h/960/format/webp/ignore-error/1" alt="xuehuayu.cn"></p>
|
|
307
|
+
<p>另外程墨 Morgan 在<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/50336226">避免 React Context 导致的重复渲染</a>一文中也提到 ContextAPI 的一个陷阱:</p>
|
|
308
|
+
<pre><code><Context.Provider
|
|
309
|
+
value={ { theme: this.state.theme, switchTheme: this.switchTheme } }
|
|
310
|
+
>
|
|
311
|
+
<div className="App">
|
|
312
|
+
<Header />
|
|
313
|
+
<Content />
|
|
314
|
+
</div>
|
|
315
|
+
</Context.Provider>
|
|
316
|
+
复制代码
|
|
317
|
+
</code></pre>
|
|
318
|
+
<p>上面的组件会在 state 变化时重新渲染整个组件树,至于为什么留给读者去思考。</p>
|
|
319
|
+
<p>所以我们一般都不会裸露地使用 Context.Provider, 而是封装为独立的 Provider 组件:</p>
|
|
320
|
+
<pre><code>exportfunctionThemeProvider(props) {
|
|
321
|
+
const [theme, switchTheme] = useState(redTheme);
|
|
322
|
+
return (
|
|
323
|
+
<Context.Providervalue={ {theme, switchTheme } }>
|
|
324
|
+
{props.children}
|
|
325
|
+
</Context.Provider>
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// 顺便暴露useTheme, 让外部必须直接使用Context
|
|
330
|
+
export function useTheme() {
|
|
331
|
+
return useContext(Context);
|
|
332
|
+
}
|
|
333
|
+
复制代码
|
|
334
|
+
</code></pre>
|
|
335
|
+
<p>现在 theme 变动就不会重新渲染整个组件树,因为 props.children 由外部传递进来,并没有发生变动。</p>
|
|
336
|
+
<p><strong>其实上面的代码还有另外一个比较难发现的陷阱(官方文档也有<a target="_blank" rel="noopener" href="https://zh-hans.reactjs.org/docs/context.html#caveats">提到</a>)</strong>:</p>
|
|
337
|
+
<pre><code>export function ThemeProvider(props) {
|
|
338
|
+
const [theme, switchTheme] = useState(redTheme);
|
|
339
|
+
return (
|
|
340
|
+
{/* 👇 💣这里每一次渲染ThemeProvider, 都会创建一个新的value(即使theme和switchTheme没有变动),
|
|
341
|
+
从而导致强制渲染所有依赖该Context的组件 */}
|
|
342
|
+
<Context.Provider value={ { theme, switchTheme } }>
|
|
343
|
+
{props.children}
|
|
344
|
+
</Context.Provider>
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
复制代码
|
|
348
|
+
</code></pre>
|
|
349
|
+
<p>所以<strong>传递给 Context 的 value 最好做一下缓存</strong>:</p>
|
|
350
|
+
<pre><code>exportfunctionThemeProvider(props) {
|
|
351
|
+
const [theme, switchTheme] = useState(redTheme);
|
|
352
|
+
const value = useMemo(() => ({ theme, switchTheme }), [theme]);
|
|
353
|
+
return<Context.Providervalue={value}>{props.children}</Context.Provider>;
|
|
354
|
+
}
|
|
355
|
+
复制代码
|
|
356
|
+
</code></pre>
|
|
357
|
+
<h2 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h2><ul>
|
|
358
|
+
<li><a target="_blank" rel="noopener" href="https://react.docschina.org/docs/optimizing-performance.html">Optimizing Performance</a> React 官方文档,最好的教程, 利用好 React 的性能分析工具。</li>
|
|
359
|
+
<li><a target="_blank" rel="noopener" href="https://medium.com/@paularmstrong/twitter-lite-and-high-performance-react-progressive-web-apps-at-scale-d28a00e780a3">Twitter Lite and High Performance React Progressive Web Apps at Scale</a> 看看 Twitter 如何优化的</li>
|
|
360
|
+
</ul>
|
|
361
|
+
</div><iframe src="/donate/?AliPayQR=https://store.xuehuayu.cn/store/public/alipay_qr.jpg&WeChatQR=https://store.xuehuayu.cn/store/public/wechat_qr.png&UnionPayQR=null&GitHub=null&BTCQR=null&BTCKEY=null&PayPal=https://www.paypal.com/paypalme/OrdinaryPerson" style="overflow-x:hidden; overflow-y:hidden; border:0xp none #fff; min-height:240px; width:100%;" frameborder="0" scrolling="no"></iframe><div><ul class="post-copyright"><li class="post-copyright-author"><strong>本文作者:</strong>雪花雨</li><li class="post-copyright-link"><strong>本文链接:</strong><a href="/article/50343.html">https://xuehuayu.cn/article/50343.html</a></li><li class="post-copyright-license"><strong>版权声明:</strong>① 标为原创的文章为博主原创,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接。② 转载文章来自网络,已标明出处,<a href="mailto:cainiaoblog@126.com">侵删</a>。</li></ul></div><br><div class="tags"><a href="/tags/%E8%BD%AC%E8%BD%BD/">转载</a></div><div class="post-nav"><a class="pre" href="/article/41011.html">如何对 React 函数式组件进行优化</a><a class="next" href="/article/46100.html">21 个 React 性能优化技巧</a></div><div id="vcomment"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@waline/client@v2/dist/waline.min.css"><script src="//cdn.jsdelivr.net/npm/@waline/client@v2/dist/waline.js"></script><script>const origin = window.location.origin
|
|
362
|
+
const serverURL = origin.includes('cainiaoblog') ? 'https://cmts.cainiaoblog.cn' : 'https://cmts.xuehuayu.cn'
|
|
363
|
+
const locale = {
|
|
364
|
+
placeholder: '请正确填写昵称和邮箱,方便接收回复通知~',
|
|
365
|
+
sofa: '沙发空缺中,还不快抢~',
|
|
366
|
+
};
|
|
367
|
+
Waline.init({
|
|
368
|
+
el: '#vcomment',
|
|
369
|
+
serverURL: serverURL,
|
|
370
|
+
pageSize: '20',
|
|
371
|
+
visitor: true, // 阅读量统计
|
|
372
|
+
requiredMeta: ['nick', 'mail'],
|
|
373
|
+
emoji: [
|
|
374
|
+
'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/weibo',
|
|
375
|
+
'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/qq',
|
|
376
|
+
'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/tw-emoji',
|
|
377
|
+
],
|
|
378
|
+
locale,
|
|
379
|
+
pageview: true
|
|
380
|
+
})
|
|
381
|
+
</script></div></div></div><div class="pure-u-1 pure-u-md-1-4 fixed-search hidden_mid_and_down"><div id="sidebar"><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/search.min.js"></script><div class="widget"><div class="widget-search"><input class="search" type="radio" name="search" value="baidu" id="baidu" checked="checked"/><label class="label" for="baidu" title="百度全站搜索">百度</label><input class="search" type="radio" name="search" value="google" id="google"/><label class="label" for="google" title="谷歌全站搜索">谷歌</label><input class="search" type="radio" name="search" value="self" id="self"/><label class="label" for="self" title="使用站内搜索">站内</label></div><div class="widget" id="search"><form class="search-form" action="//www.baidu.com/baidu" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="word" maxlength="30" placeholder="百度全站搜索"/><input type="hidden" name="si" value="xuehuayu.cn"/><input type="hidden" name="cl" value="3"/><input type="hidden" name="ct" value="2097152"/><input type="hidden" name="s" value="on"/><input class="search-submit" type="submit" value=""/></form></div></div><script>$('input[type=radio][name=search]').change(function() {
|
|
382
|
+
var val = $(this).val()
|
|
383
|
+
var self = '<div class="search-form"><input id="local-search-input" placeholder="站内搜索,首次慢" type="search" name="q" results="0"><input class="search-submit" type="submit" value=""/><div id="local-search-result"></div></div>'
|
|
384
|
+
var google = '<form class="search-form" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="q" maxlength="30" placeholder="谷歌全站搜索"><input type="hidden" name="sitesearch" value="xuehuayu.cn"><input class="search-submit" type="submit" value=""/></form>'
|
|
385
|
+
var baidu = '<form class="search-form" action="//www.baidu.com/baidu" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="word" maxlength="30" placeholder="百度全站搜索"><input type="hidden" name="si" value="xuehuayu.cn"><input type="hidden" name="cl" value="3"><input type="hidden" name="ct" value="2097152"><input type="hidden" name="s" value="on"><input class="search-submit" type="submit" value=""/></form>'
|
|
386
|
+
|
|
387
|
+
if (val === 'self') {
|
|
388
|
+
$('#search').html(self)
|
|
389
|
+
var search_path = 'search.xml';
|
|
390
|
+
if (search_path.length == 0) {
|
|
391
|
+
search_path = 'search.xml';
|
|
392
|
+
}
|
|
393
|
+
var path = 'https://cdn.staticaly.com/gh/npljy/npljy.github.io/main/' + search_path;
|
|
394
|
+
searchFunc(path, 'local-search-input', 'local-search-result');
|
|
395
|
+
} else if (val === 'baidu') {
|
|
396
|
+
$('#search').html(baidu)
|
|
397
|
+
} else if (val === 'google') {
|
|
398
|
+
$('#search').html(google)
|
|
399
|
+
}
|
|
400
|
+
})</script><div class="widget widget-wxmp"><img alt="微信公众号" width="100%" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/mp-mini.jpg"/></div><div class="widget widget-categories"><div class="widget-title"><i class="fa fa-folder-o"> 分类</i></div><ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/CDN/">CDN</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/IDE/">IDE</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hexo/">hexo</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%85%AC%E5%85%B1%E8%8A%82%E6%97%A5/">公共节日</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%88%86%E4%BA%AB/">分享</a><span class="category-list-count">29</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/">前端</a><span class="category-list-count">191</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a><span class="category-list-count">1</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/%E6%B5%8F%E8%A7%88%E5%99%A8/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/">网络协议</a><span class="category-list-count">1</span></li></ul></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%8D%9A%E5%AE%A2/">博客</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B7%A5%E5%85%B7/">工具</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B9%BF%E5%91%8A%E8%BF%87%E6%BB%A4/">广告过滤</a><span class="category-list-count">8</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B9%BF%E5%91%8A%E8%BF%87%E6%BB%A4/%E8%A7%86%E9%A2%91%E7%94%B5%E8%A7%86%E5%B0%8F%E8%AF%B4%E6%BC%AB%E7%94%BB%E8%B5%84%E8%AE%AF%E9%9F%B3%E4%B9%90/">视频电视小说漫画资讯音乐</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%AD%A3%E5%88%99/">正则</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E7%AE%97%E6%B3%95/">算法</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E8%B5%84%E8%AE%AF/">资讯</a><span class="category-list-count">16</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E8%BD%BB%E6%9D%BE%E4%B8%80%E5%88%BB/">轻松一刻</a><span class="category-list-count">1</span></li></ul></div><div class="widget widget-tags"><div class="widget-title"><i class="fa fa-star-o"> 标签</i></div><div class="tagcloud"><a href="/tags/%E5%8E%9F%E5%88%9B/" style="font-size: 15px;">原创</a> <a href="/tags/%E8%BD%AC%E8%BD%BD/" style="font-size: 15px;">转载</a> <a href="/tags/%E6%89%8B%E5%86%99/" style="font-size: 15px;">手写</a> <a href="/tags/%E7%96%AB%E6%83%85/" style="font-size: 15px;">疫情</a> <a href="/tags/%E5%A8%B1%E4%B9%90/" style="font-size: 15px;">娱乐</a></div></div><div class="widget widget-recent-posts"><div class="widget-title"><i class="fa fa-file-o"> 最近文章</i></div><ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/article/c5576490.html">面试准备</a></li><li class="post-list-item"><a class="post-list-link" href="/article/84c9ccd6.html">精读《SolidJS》</a></li><li class="post-list-item"><a class="post-list-link" href="/article/53803e6.html">git提交注释规范</a></li><li class="post-list-item"><a class="post-list-link" href="/article/a4145266.html">前端数组拍平flat一行代码</a></li><li class="post-list-item"><a class="post-list-link" href="/article/bedea419.html">一道前端this面试题</a></li><li class="post-list-item"><a class="post-list-link" href="/article/bf7e7421.html">git多账号配置</a></li></ul></div><div class="widget widget-links"><div class="widget-title"><i class="fa fa-external-link"> 友情链接</i></div><ul></ul><a href="https://github.com/npljy?utm_source=xuehuayu.cn" title="GitHub" target="_blank">GitHub</a><ul></ul><a href="https://laonongmin.online?utm_source=xuehuayu.cn" title="看看" target="_blank">看看</a><ul></ul><a href="https://cainiaoblog.cn?utm_source=xuehuayu.cn" title="菜鸟博客" target="_blank">菜鸟博客</a><ul></ul><a href="mailto:cainiaoblog@126.com" title="友链联系" target="_blank">友链联系</a></div></div></div><div class="pure-u-1 pure-u-md-3-4"><div id="footer"><div class="flex-block justify-center align-center flex-wrap"><a class="gxba-link" id="gxba" rel="nofollow" target="_blank" href="http://beian.miit.gov.cn/">京ICP备20007647号-2</a><a class="gaba-link" id="gaba-link" rel="nofollow" target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802031264"><img class="nofancybox" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/gaba.png" alt=""/><span id="gaba">京公网安备 11010802031264号</span><span style="padding-right: 10px;"></span></a><span>Copyright © 2023 </span><a href="/." rel="nofollow">前端壹菜鸟. </a><script>(function(){
|
|
401
|
+
var cnb =window.location.origin.indexOf('cainiaoblog') !==-1
|
|
402
|
+
if (cnb) {
|
|
403
|
+
var gxba =document.getElementById('gxba')
|
|
404
|
+
var gaba =document.getElementById('gaba')
|
|
405
|
+
var gabaLink =document.getElementById('gaba-link')
|
|
406
|
+
gxba.innerText ='京ICP备20007647号-1'
|
|
407
|
+
gaba.innerText ='京公网安备 11010802031254号'
|
|
408
|
+
gabaLink.setAttribute('href','http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802031254')
|
|
409
|
+
}
|
|
410
|
+
})()</script></div><div class="flex-block justify-center align-center flex-wrap"><a rel="nofollow" target="_blank" href="https://v6.51.la/s/Guz3lwHCsVme9Cu"><div class="busuanzi_container" id="busuanzi_container"><span class="busuanzi_container_site_pv" id="busuanzi_container_site_pv">访问量:<span id="busuanzi_value_site_pv"><i class="fa fa-spinner"></i></span></span><span class="busuanzi_container_site_uv" id="busuanzi_container_site_uv">访客数:<span id="busuanzi_value_site_uv"><i class="fa fa-spinner"></i></span></span><span style="padding-right: 10px;"></span></div></a><a rel="nofollow" target="_blank" href="https://www.upyun.com/?utm_source=lianmeng&utm_medium=referral"><span style="font-weight:bold;letter-spacing: 1px;">本网站由 </span><img class="nofancybox" height="32" style="vertical-align: middle" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/upy_logo.min.svg" alt=""/><span style="font-weight:bold;letter-spacing: 1px;">提供CDN加速/云存储服务</span></a><span style="padding-right: 10px;"></span><a rel="nofollow" style="font-size:18px;font-weight:bold;vertical-align: middle" target="_blank" title="注册就送代金券可直接使用" href="https://console.upyun.com/register/?invite=HyDsjZHIL">注册</a></div></div></div></div><a class="show" id="rocket" href="#top"></a><div class="darkmode-toggle">🌓</div><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/totop.min.js" async></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/dark.min.js" async></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/codeblock-resizer.min.js"></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/smartresize.min.js"></script></div></body></html>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!DOCTYPE html><html lang="zh-CN" data-dark><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"><meta content="yes" name="apple-mobile-web-app-capable"><meta content="black-translucent" name="apple-mobile-web-app-status-bar-style"><meta content="telephone=no" name="format-detection"><meta name="description" content="前端壹菜鸟,记录工作难题,关注前端知识,收集精彩博文,做技术的搬运工"><meta name="msvalidate.01" content="0FE4D8B3381D3D87088996B886E1E2BD"><title>请求报错问题provisional headers are shown解决办法 | 前端壹菜鸟</title><link rel="stylesheet" type="text/css" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/css/style.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/normalize.css@latest/normalize.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/purecss@latest/build/pure-min.min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/purecss@latest/build/grids-responsive-min.css"><link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css"><link rel="icon" mask="" sizes="any" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.ico"><link rel="Shortcut Icon" type="image/x-icon" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.ico"><link rel="apple-touch-icon" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.png"><link rel="apple-touch-icon-precomposed" href="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/blog.png"><link rel="alternate" type="application/atom+xml" href="/atom.xml"><script type="text/javascript" src="//cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js"></script><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8385136408348258"></script><script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" async></script><script>(function(){
|
|
2
|
+
var bp = document.createElement('script');
|
|
3
|
+
var curProtocol = window.location.protocol.split(':')[0];
|
|
4
|
+
if (curProtocol === 'https'){
|
|
5
|
+
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
|
|
6
|
+
}
|
|
7
|
+
else{
|
|
8
|
+
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
|
|
9
|
+
}
|
|
10
|
+
var s = document.getElementsByTagName("script")[0];
|
|
11
|
+
s.parentNode.insertBefore(bp, s);
|
|
12
|
+
})();
|
|
13
|
+
</script><script>(function(){
|
|
14
|
+
var src = 'https://jspassport.ssl.qhimg.com/11.0.1.js?d182b3f28525f2db83acfaaf6e696dba';
|
|
15
|
+
document.write('<script src="' + src + '" id="sozz"><\/script>');
|
|
16
|
+
})();
|
|
17
|
+
</script><script>var _hmt=_hmt||[];(function(){var hm=document.createElement("script");hm.src='https://hm.baidu.com/hm.js?011f0b44e8452bfa57fbfa23c5fe7683';var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm, s);})();
|
|
18
|
+
</script><script async src="https://www.googletagmanager.com/gtag/js?id=UA-150860401-1"></script><script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments);};gtag('js',new Date());gtag('config','UA-150860401-1');
|
|
19
|
+
</script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/fixedPage.min.js"></script><meta name="generator" content="Hexo 6.3.0"></head><body><div class="body_container"><div id="header"><div class="site-name"><a id="logo" href="/.">前端壹菜鸟</a><p class="description">关注前端知识,收集精彩博文,做技术的搬运工</p></div><div id="nav-menu"><a class="current" href="/." target="_self"><i class="fa fa-home"> 首页</i></a><a href="/archives/" target="_self"><i class="fa fa-archive"> 归档</i></a><a href="/guestbook/" target="_self"><i class="fa fa-comments"> 留言</i></a><a href="/about/" target="_self"><i class="fa fa-user"> 关于</i></a><a href="https://laonongmin.online/" target="_target"><i class="fa fa-group"> 看看</i></a><a href="https://love.xuehuayu.cn/" target="_target"><i class="fa fa-heart"> LOVE</i></a></div></div><div class="pure-g" id="layout"><div class="pure-u-1 pure-u-md-3-4"><div class="content_container"><div class="post"><h1 class="post-title c-post">请求报错问题provisional headers are shown解决办法</h1><div class="post-meta"><span class="date">2019-10-28</span><span> | </span><span class="tag original"><a href="/tags/%E5%8E%9F%E5%88%9B/">原创 </a></span><span> | </span><span class="category"><a href="/categories/%E5%89%8D%E7%AB%AF/">前端 </a></span><span id="busuanzi_container_page_pv"> | <span id="busuanzi_value_page_pv"><i class="fa fa-spinner"></i></span><span> 阅读</span></span><span class="post-time"><span class="post-meta-item-text"> | </span><span class="post-meta-item-icon"><i class="fa fa-keyboard-o"></i><span class="post-count"> 324</span><span class="post-meta-item-text"> 字</span></span></span><span class="post-time"> | <span class="post-meta-item-icon"><i class="fa fa-hourglass-half"></i><span class="post-count"> 1</span><span class="post-meta-item-text"> 分钟</span></span></span></div><a class="disqus-comment-count" href="/article/50510.html#vcomment"><span class="waline-comment-count" data-path="/article/50510.html"></span><span> 条评论</span></a><div class="post-content"><p>最近项目中,遇到axios请求总是发生provisional headers are shown问题,网上查找了好多解决办法,都是千篇一律,不外乎三种。然而并没有说出个所以然来</p>
|
|
20
|
+
<span id="more"></span>
|
|
21
|
+
<p>1.请求跨域被拦截<br>2.被扩展程序拦截<br>3.服务器未及时响应</p>
|
|
22
|
+
<p>后端也配置了corsconfig,后端研发检查了所有代码都没有问题,浏览器也安装任何扩展。</p>
|
|
23
|
+
<hr>
|
|
24
|
+
<p>废话不多说,说解决办法,可能会有下面几种情况:</p>
|
|
25
|
+
<ol>
|
|
26
|
+
<li>防火墙没有关闭,关闭之后,可以正常请求了。</li>
|
|
27
|
+
<li>没有权限,前端请求中没有正确的带上校验信息,比如cookie中的token,或者请求头中没有带上Authorization之类的验证信息<br><code>检查浏览器控制台network看是否有带上验证信息,验证信息是否正确</code></li>
|
|
28
|
+
<li>ajax每次发送get,post等请求之前,会自动发option请求,看是否是浏览器控制台的option请求报<code>provisional headers are shown</code>,如果是可能是服务器只设置了允许get,post等请求,解决方法是后台如果接收到option请求,就忽略校验,直接通过。</li>
|
|
29
|
+
</ol>
|
|
30
|
+
<blockquote>
|
|
31
|
+
<p>跨域预检请求,请参考:<a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/OPTIONS">HTTP 的 OPTIONS 方法</a><br><a target="_blank" rel="noopener" href="https://www.ruanyifeng.com/blog/2016/04/cors.html">阮一峰:跨域资源共享 CORS 详解</a></p>
|
|
32
|
+
</blockquote>
|
|
33
|
+
</div><iframe src="/donate/?AliPayQR=https://store.xuehuayu.cn/store/public/alipay_qr.jpg&WeChatQR=https://store.xuehuayu.cn/store/public/wechat_qr.png&UnionPayQR=null&GitHub=null&BTCQR=null&BTCKEY=null&PayPal=https://www.paypal.com/paypalme/OrdinaryPerson" style="overflow-x:hidden; overflow-y:hidden; border:0xp none #fff; min-height:240px; width:100%;" frameborder="0" scrolling="no"></iframe><div><ul class="post-copyright"><li class="post-copyright-author"><strong>本文作者:</strong>雪花雨</li><li class="post-copyright-link"><strong>本文链接:</strong><a href="/article/50510.html">https://xuehuayu.cn/article/50510.html</a></li><li class="post-copyright-license"><strong>版权声明:</strong>① 标为原创的文章为博主原创,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接。② 转载文章来自网络,已标明出处,<a href="mailto:cainiaoblog@126.com">侵删</a>。</li></ul></div><br><div class="tags"><a href="/tags/%E5%8E%9F%E5%88%9B/">原创</a></div><div class="post-nav"><a class="pre" href="/article/53698.html">连续拿到4个大厂offer的面试总结</a><a class="next" href="/article/31826.html">Electron 7.0.0 发布</a></div><div id="vcomment"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@waline/client@v2/dist/waline.min.css"><script src="//cdn.jsdelivr.net/npm/@waline/client@v2/dist/waline.js"></script><script>const origin = window.location.origin
|
|
34
|
+
const serverURL = origin.includes('cainiaoblog') ? 'https://cmts.cainiaoblog.cn' : 'https://cmts.xuehuayu.cn'
|
|
35
|
+
const locale = {
|
|
36
|
+
placeholder: '请正确填写昵称和邮箱,方便接收回复通知~',
|
|
37
|
+
sofa: '沙发空缺中,还不快抢~',
|
|
38
|
+
};
|
|
39
|
+
Waline.init({
|
|
40
|
+
el: '#vcomment',
|
|
41
|
+
serverURL: serverURL,
|
|
42
|
+
pageSize: '20',
|
|
43
|
+
visitor: true, // 阅读量统计
|
|
44
|
+
requiredMeta: ['nick', 'mail'],
|
|
45
|
+
emoji: [
|
|
46
|
+
'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/weibo',
|
|
47
|
+
'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/qq',
|
|
48
|
+
'https://cdn.jsdelivr.net/gh/walinejs/emojis@1.0.0/tw-emoji',
|
|
49
|
+
],
|
|
50
|
+
locale,
|
|
51
|
+
pageview: true
|
|
52
|
+
})
|
|
53
|
+
</script></div></div></div><div class="pure-u-1 pure-u-md-1-4 fixed-search hidden_mid_and_down"><div id="sidebar"><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/search.min.js"></script><div class="widget"><div class="widget-search"><input class="search" type="radio" name="search" value="baidu" id="baidu" checked="checked"/><label class="label" for="baidu" title="百度全站搜索">百度</label><input class="search" type="radio" name="search" value="google" id="google"/><label class="label" for="google" title="谷歌全站搜索">谷歌</label><input class="search" type="radio" name="search" value="self" id="self"/><label class="label" for="self" title="使用站内搜索">站内</label></div><div class="widget" id="search"><form class="search-form" action="//www.baidu.com/baidu" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="word" maxlength="30" placeholder="百度全站搜索"/><input type="hidden" name="si" value="xuehuayu.cn"/><input type="hidden" name="cl" value="3"/><input type="hidden" name="ct" value="2097152"/><input type="hidden" name="s" value="on"/><input class="search-submit" type="submit" value=""/></form></div></div><script>$('input[type=radio][name=search]').change(function() {
|
|
54
|
+
var val = $(this).val()
|
|
55
|
+
var self = '<div class="search-form"><input id="local-search-input" placeholder="站内搜索,首次慢" type="search" name="q" results="0"><input class="search-submit" type="submit" value=""/><div id="local-search-result"></div></div>'
|
|
56
|
+
var google = '<form class="search-form" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="q" maxlength="30" placeholder="谷歌全站搜索"><input type="hidden" name="sitesearch" value="xuehuayu.cn"><input class="search-submit" type="submit" value=""/></form>'
|
|
57
|
+
var baidu = '<form class="search-form" action="//www.baidu.com/baidu" method="get" accept-charset="utf-8" target="_blank"><input type="search" name="word" maxlength="30" placeholder="百度全站搜索"><input type="hidden" name="si" value="xuehuayu.cn"><input type="hidden" name="cl" value="3"><input type="hidden" name="ct" value="2097152"><input type="hidden" name="s" value="on"><input class="search-submit" type="submit" value=""/></form>'
|
|
58
|
+
|
|
59
|
+
if (val === 'self') {
|
|
60
|
+
$('#search').html(self)
|
|
61
|
+
var search_path = 'search.xml';
|
|
62
|
+
if (search_path.length == 0) {
|
|
63
|
+
search_path = 'search.xml';
|
|
64
|
+
}
|
|
65
|
+
var path = 'https://cdn.staticaly.com/gh/npljy/npljy.github.io/main/' + search_path;
|
|
66
|
+
searchFunc(path, 'local-search-input', 'local-search-result');
|
|
67
|
+
} else if (val === 'baidu') {
|
|
68
|
+
$('#search').html(baidu)
|
|
69
|
+
} else if (val === 'google') {
|
|
70
|
+
$('#search').html(google)
|
|
71
|
+
}
|
|
72
|
+
})</script><div class="widget widget-wxmp"><img alt="微信公众号" width="100%" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/mp-mini.jpg"/></div><div class="widget widget-categories"><div class="widget-title"><i class="fa fa-folder-o"> 分类</i></div><ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/CDN/">CDN</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/IDE/">IDE</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hexo/">hexo</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%85%AC%E5%85%B1%E8%8A%82%E6%97%A5/">公共节日</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%88%86%E4%BA%AB/">分享</a><span class="category-list-count">29</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/">前端</a><span class="category-list-count">191</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a><span class="category-list-count">1</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%89%8D%E7%AB%AF/%E6%B5%8F%E8%A7%88%E5%99%A8/%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE/">网络协议</a><span class="category-list-count">1</span></li></ul></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%8D%9A%E5%AE%A2/">博客</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B7%A5%E5%85%B7/">工具</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B9%BF%E5%91%8A%E8%BF%87%E6%BB%A4/">广告过滤</a><span class="category-list-count">8</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/%E5%B9%BF%E5%91%8A%E8%BF%87%E6%BB%A4/%E8%A7%86%E9%A2%91%E7%94%B5%E8%A7%86%E5%B0%8F%E8%AF%B4%E6%BC%AB%E7%94%BB%E8%B5%84%E8%AE%AF%E9%9F%B3%E4%B9%90/">视频电视小说漫画资讯音乐</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%AD%A3%E5%88%99/">正则</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E6%B5%8F%E8%A7%88%E5%99%A8/">浏览器</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E7%AE%97%E6%B3%95/">算法</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E8%B5%84%E8%AE%AF/">资讯</a><span class="category-list-count">16</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/%E8%BD%BB%E6%9D%BE%E4%B8%80%E5%88%BB/">轻松一刻</a><span class="category-list-count">1</span></li></ul></div><div class="widget widget-tags"><div class="widget-title"><i class="fa fa-star-o"> 标签</i></div><div class="tagcloud"><a href="/tags/%E5%8E%9F%E5%88%9B/" style="font-size: 15px;">原创</a> <a href="/tags/%E8%BD%AC%E8%BD%BD/" style="font-size: 15px;">转载</a> <a href="/tags/%E6%89%8B%E5%86%99/" style="font-size: 15px;">手写</a> <a href="/tags/%E7%96%AB%E6%83%85/" style="font-size: 15px;">疫情</a> <a href="/tags/%E5%A8%B1%E4%B9%90/" style="font-size: 15px;">娱乐</a></div></div><div class="widget widget-recent-posts"><div class="widget-title"><i class="fa fa-file-o"> 最近文章</i></div><ul class="post-list"><li class="post-list-item"><a class="post-list-link" href="/article/c5576490.html">面试准备</a></li><li class="post-list-item"><a class="post-list-link" href="/article/84c9ccd6.html">精读《SolidJS》</a></li><li class="post-list-item"><a class="post-list-link" href="/article/53803e6.html">git提交注释规范</a></li><li class="post-list-item"><a class="post-list-link" href="/article/a4145266.html">前端数组拍平flat一行代码</a></li><li class="post-list-item"><a class="post-list-link" href="/article/bedea419.html">一道前端this面试题</a></li><li class="post-list-item"><a class="post-list-link" href="/article/bf7e7421.html">git多账号配置</a></li></ul></div><div class="widget widget-links"><div class="widget-title"><i class="fa fa-external-link"> 友情链接</i></div><ul></ul><a href="https://github.com/npljy?utm_source=xuehuayu.cn" title="GitHub" target="_blank">GitHub</a><ul></ul><a href="https://laonongmin.online?utm_source=xuehuayu.cn" title="看看" target="_blank">看看</a><ul></ul><a href="https://cainiaoblog.cn?utm_source=xuehuayu.cn" title="菜鸟博客" target="_blank">菜鸟博客</a><ul></ul><a href="mailto:cainiaoblog@126.com" title="友链联系" target="_blank">友链联系</a></div></div></div><div class="pure-u-1 pure-u-md-3-4"><div id="footer"><div class="flex-block justify-center align-center flex-wrap"><a class="gxba-link" id="gxba" rel="nofollow" target="_blank" href="http://beian.miit.gov.cn/">京ICP备20007647号-2</a><a class="gaba-link" id="gaba-link" rel="nofollow" target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802031264"><img class="nofancybox" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/gaba.png" alt=""/><span id="gaba">京公网安备 11010802031264号</span><span style="padding-right: 10px;"></span></a><span>Copyright © 2023 </span><a href="/." rel="nofollow">前端壹菜鸟. </a><script>(function(){
|
|
73
|
+
var cnb =window.location.origin.indexOf('cainiaoblog') !==-1
|
|
74
|
+
if (cnb) {
|
|
75
|
+
var gxba =document.getElementById('gxba')
|
|
76
|
+
var gaba =document.getElementById('gaba')
|
|
77
|
+
var gabaLink =document.getElementById('gaba-link')
|
|
78
|
+
gxba.innerText ='京ICP备20007647号-1'
|
|
79
|
+
gaba.innerText ='京公网安备 11010802031254号'
|
|
80
|
+
gabaLink.setAttribute('href','http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010802031254')
|
|
81
|
+
}
|
|
82
|
+
})()</script></div><div class="flex-block justify-center align-center flex-wrap"><a rel="nofollow" target="_blank" href="https://v6.51.la/s/Guz3lwHCsVme9Cu"><div class="busuanzi_container" id="busuanzi_container"><span class="busuanzi_container_site_pv" id="busuanzi_container_site_pv">访问量:<span id="busuanzi_value_site_pv"><i class="fa fa-spinner"></i></span></span><span class="busuanzi_container_site_uv" id="busuanzi_container_site_uv">访客数:<span id="busuanzi_value_site_uv"><i class="fa fa-spinner"></i></span></span><span style="padding-right: 10px;"></span></div></a><a rel="nofollow" target="_blank" href="https://www.upyun.com/?utm_source=lianmeng&utm_medium=referral"><span style="font-weight:bold;letter-spacing: 1px;">本网站由 </span><img class="nofancybox" height="32" style="vertical-align: middle" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/img/upy_logo.min.svg" alt=""/><span style="font-weight:bold;letter-spacing: 1px;">提供CDN加速/云存储服务</span></a><span style="padding-right: 10px;"></span><a rel="nofollow" style="font-size:18px;font-weight:bold;vertical-align: middle" target="_blank" title="注册就送代金券可直接使用" href="https://console.upyun.com/register/?invite=HyDsjZHIL">注册</a></div></div></div></div><a class="show" id="rocket" href="#top"></a><div class="darkmode-toggle">🌓</div><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/totop.min.js" async></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/dark.min.js" async></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/codeblock-resizer.min.js"></script><script type="text/javascript" src="//cdn.staticaly.com/gh/npljy/npljy.github.io/main/js/smartresize.min.js"></script></div></body></html>
|