Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
電商網(wǎng)站遷移到一個(gè)新的設(shè)計(jì)、平臺(tái)或領(lǐng)域意味著你必須非常嚴(yán)謹(jǐn)?shù)貓?zhí)行該操作,否則你的SEO就會(huì)受到影響,從而降低流量、轉(zhuǎn)化率和收入。如果在沒(méi)有任何操作策略下執(zhí)行該工作,甚至?xí)咕W(wǎng)站受到攻擊。在電子商務(wù)網(wǎng)站遷移之前做好準(zhǔn)備是確保其持續(xù)成功的關(guān)鍵,雖然在遷移站點(diǎn)時(shí)SEO通常會(huì)出現(xiàn)下降,但如果啟動(dòng)之前修復(fù)錯(cuò)誤實(shí)際上可以幫助你保持穩(wěn)定的流量。
為此,本文將分享五個(gè)網(wǎng)站階段遷移檢查步驟,以盡量減少網(wǎng)站遷移所帶來(lái)的任何潛在的SEO負(fù)面影響。
·網(wǎng)站設(shè)計(jì)過(guò)時(shí)
·你的業(yè)務(wù)更改了服務(wù)提供,因此需要添加新信息或更改現(xiàn)有信息以使業(yè)務(wù)更具有時(shí)效性。
·重新命名(當(dāng)業(yè)務(wù)名稱更改時(shí),這可能涉及遷移到一個(gè)新域)。
·CMS(內(nèi)部管理系統(tǒng))平臺(tái)存在一些問(wèn)題,你想要切換到一個(gè)具有更多或不同的強(qiáng)大功能或成本更低的平臺(tái)。
·網(wǎng)站沒(méi)有轉(zhuǎn)換,你希望從頭開(kāi)始創(chuàng)建一個(gè)新域
接下來(lái)將深入討論成功遷移的具體細(xì)節(jié),從涉及的風(fēng)險(xiǎn)開(kāi)始。
低SEO風(fēng)險(xiǎn):網(wǎng)站重新設(shè)計(jì)
當(dāng)遷移范圍僅限于簡(jiǎn)單地更改網(wǎng)站的設(shè)計(jì)時(shí),風(fēng)險(xiǎn)相對(duì)較低。原因很簡(jiǎn)單,因?yàn)閁RL并沒(méi)有更改,因此你也沒(méi)有必要從外部代理機(jī)構(gòu)來(lái)尋求幫助以保護(hù)SEO不受影響。
中等SEO風(fēng)險(xiǎn):URL /更改(平臺(tái)未更改)
當(dāng)域發(fā)生更改時(shí)或者需要具有豐富重定向的新URL結(jié)構(gòu)的更改時(shí),你就需要進(jìn)行仔細(xì)地監(jiān)視。因?yàn)槿魏蜺RL更改都會(huì)給你的SEO帶來(lái)風(fēng)險(xiǎn),因此網(wǎng)站的新URL需要被索引,這一目標(biāo)是通過(guò)使URL易于抓取,從而使它們?cè)诎l(fā)布后被谷歌快速索引。無(wú)論實(shí)際的設(shè)計(jì)是否發(fā)生了變化,新的URL路徑都是網(wǎng)站SEO的基本改變,應(yīng)該加以監(jiān)控。
中等SEO風(fēng)險(xiǎn):電商平臺(tái)的變化
通常,平臺(tái)更改意味著站點(diǎn)的URL也會(huì)更改。這是因?yàn)楦鞣N電子商務(wù)平臺(tái)的url結(jié)構(gòu)不同。例如作為指向Shopify“collections”中的產(chǎn)品的路徑,URL結(jié)構(gòu)必須是domain.com/products/productname或domain.com/collections/collectionname/products/productname
與此同時(shí),WordPress和其他CMS(內(nèi)容管理系統(tǒng))都有自己的URL結(jié)構(gòu),且需求不同。這就是為什么在很多情況下,維護(hù)原始URL是不可能的的原因。平臺(tái)的變化也會(huì)帶來(lái)核心功能丟失的風(fēng)險(xiǎn),而這些核心功能正是SEO(或其他營(yíng)銷(xiāo)渠道)目前所受益的。在遷移平臺(tái)時(shí),評(píng)估和最小化這樣的風(fēng)險(xiǎn)才是關(guān)鍵。
高SEO風(fēng)險(xiǎn):域遷移
無(wú)論URL或設(shè)計(jì)更改如何,遷移電子商務(wù)網(wǎng)站的域都存在很大的風(fēng)險(xiǎn)。問(wèn)題是,域名在谷歌中遺留了很多的歷史。因此當(dāng)你從零開(kāi)始時(shí),必然會(huì)有所損失。在這種情況下,就要做更多的工作來(lái)減輕SEO的影響和流量損失。
現(xiàn)在你已經(jīng)了解了其中的風(fēng)險(xiǎn),以下是遷移網(wǎng)站需要驗(yàn)證的所有因素的詳細(xì)列表。
由于這是一個(gè)從一個(gè)平臺(tái)到另一個(gè)平臺(tái)的數(shù)據(jù)遷移過(guò)程,所以你將使用舊站點(diǎn)的數(shù)據(jù)作為基準(zhǔn),以便在稍后的步驟中參考和比較新站點(diǎn)。目標(biāo)是在將開(kāi)發(fā)站點(diǎn)的功能與活動(dòng)站點(diǎn)進(jìn)行比較時(shí),以盡可能少的差異啟動(dòng)開(kāi)發(fā)網(wǎng)站。
步驟1:使用DeepCrawl或Screaming Frog抓取當(dāng)前域
Screaming Frog是一種應(yīng)用廣泛的工具,其數(shù)據(jù)輸出適合于該過(guò)程。
通將DeepCrawl用于較大的站點(diǎn),而Screaming Frog是作為較小站點(diǎn)的更便宜和更容易的選擇。也就是說(shuō),你可以使用你選擇的抓取工具。
抓取當(dāng)前活動(dòng)域可以提供網(wǎng)站上的URL列表,以及關(guān)于這些URL的各種數(shù)據(jù),從而使用這些數(shù)據(jù)進(jìn)行檢查和基準(zhǔn)測(cè)試。
步驟2:執(zhí)行 Google Search Console(谷歌站長(zhǎng)工具)分析
審查網(wǎng)站的谷歌相關(guān)數(shù)據(jù)非常重要。數(shù)據(jù)在GSC中以儀表板格式顯示,你將考慮:
·導(dǎo)出站點(diǎn)的CSV數(shù)據(jù)
·是否需要將結(jié)構(gòu)化數(shù)據(jù)轉(zhuǎn)移到新網(wǎng)站?
·hreflang標(biāo)簽需要轉(zhuǎn)到新站點(diǎn)嗎?
·是否需要在啟動(dòng)前處理404錯(cuò)誤?
步驟3:抓取并分析舊網(wǎng)站
現(xiàn)在你已經(jīng)有了抓取數(shù)據(jù)和谷歌的數(shù)據(jù),你將記錄下以下幾點(diǎn),以便能夠?qū)⑺鼈兣c新站點(diǎn)進(jìn)行比較:
·在源代碼中查找Meta robots nofollow標(biāo)簽
·查找?guī)в衝oindex(禁止索引)標(biāo)記的頁(yè)面
·審查規(guī)范標(biāo)簽
·審查標(biāo)題標(biāo)簽
·審查元描述標(biāo)簽
·審查標(biāo)題(h1, h2等)的用法
· 在一個(gè)文件中收集所有已知的實(shí)時(shí)URL(根據(jù)網(wǎng)站抓取、serp抓取、GSC/Google Search Console、GA/Google Analytics等)。
接下來(lái)你就要進(jìn)行技術(shù)工作,檢查可能的錯(cuò)誤,并采取必要的步驟來(lái)測(cè)試和解決它們。
步驟1:檢查服務(wù)器更改
要求開(kāi)發(fā)人員在新服務(wù)器上托管開(kāi)發(fā)網(wǎng)站以識(shí)別潛在的問(wèn)題,不要忘記要求開(kāi)發(fā)人員使用robots.txt文件阻止搜索引擎機(jī)器人訪問(wèn)開(kāi)發(fā)站點(diǎn)。
步驟2:建立301重定向策略
要獲得新的URL索引,實(shí)現(xiàn)重定向的系統(tǒng)方法是至關(guān)重要的一步。
·使用網(wǎng)站抓取數(shù)據(jù)制定301重定向策略;
·記錄如何實(shí)現(xiàn)重定向策略,以及由誰(shuí)負(fù)責(zé),每個(gè)人都應(yīng)該在如何構(gòu)建和實(shí)現(xiàn)重定向的問(wèn)題上保持一致;
·是否存在需要更新的舊版重定向;
此外你還將在啟動(dòng)或遷移時(shí)檢查重定向是否成功。
步驟3:進(jìn)行技術(shù)開(kāi)發(fā)網(wǎng)站優(yōu)化
進(jìn)行技術(shù)審核是成功的關(guān)鍵:
·查看新站點(diǎn)的網(wǎng)站地圖和線框圖;
·確保站點(diǎn)被阻止索引;
·驗(yàn)證自定義404錯(cuò)誤頁(yè)面是否存在&正確地發(fā)出404標(biāo)題響應(yīng)。404頁(yè)面標(biāo)題應(yīng)該始終為“頁(yè)面未找到”(或類似的),這樣就可以在Google Analytics中找到錯(cuò)誤(也就是用戶訪問(wèn)的錯(cuò)誤);
·抓取開(kāi)發(fā)站點(diǎn);修正404和soft 404;
·確保你不希望在開(kāi)發(fā)網(wǎng)站上編制索引的鏈接是Nofollowed(無(wú)法追蹤)的;
·測(cè)試重定向;
·使用多個(gè)設(shè)備瀏覽開(kāi)發(fā)網(wǎng)站;
·計(jì)劃更快的索引;創(chuàng)建一個(gè)包含所有舊URL的XML站點(diǎn)地圖(如有必要),并計(jì)劃在網(wǎng)站啟動(dòng)后保留它;
·測(cè)試和提高網(wǎng)站速度,盡可能多的開(kāi)發(fā)網(wǎng)站。
由于開(kāi)發(fā)網(wǎng)站的速度只是一個(gè)估計(jì)值,所以你需要讓開(kāi)發(fā)團(tuán)隊(duì)幫助你了解哪些地方還存在不足,以及你可以做些什么來(lái)改進(jìn)它。
步驟4:確定分析遷移策略
·將分析代碼添加到開(kāi)發(fā)站點(diǎn)。(阻止訪問(wèn)此站點(diǎn)的團(tuán)隊(duì)成員的IP);
·目標(biāo):編制一個(gè)URL列表,以便在新站點(diǎn)上線時(shí)更新分析目標(biāo);
·檢查網(wǎng)站上不同類型網(wǎng)頁(yè)的移動(dòng)設(shè)備友好性;
·檢查參數(shù)是否按預(yù)期運(yùn)行(并且確保在頁(yè)面重新加載或重定向期間,不會(huì)從URL中刪除關(guān)鍵跟蹤參數(shù));
·檢查谷歌站長(zhǎng)工具中的參數(shù)報(bào)告是否存在重復(fù)內(nèi)容問(wèn)題(舊谷歌站長(zhǎng)工具的此功能可能不會(huì)長(zhǎng)時(shí)間保留);
·檢查谷歌分析以確保本網(wǎng)站不能成為其自己的引用頁(yè);
·社交媒體共享:編制社交次數(shù)最多的網(wǎng)址列表。保持舊的嵌入代碼以保持社交計(jì)數(shù)。如果沒(méi)有值得重視的頁(yè)面,請(qǐng)不要浪費(fèi)開(kāi)發(fā)工作來(lái)實(shí)行這一點(diǎn)。
這個(gè)階段的主要步驟如下:
·將舊網(wǎng)站與新網(wǎng)站相比較;
·為將要修復(fù)的內(nèi)容列一個(gè)清單,目的是在遷移期間使流量盡可能接近持平。
內(nèi)容
·網(wǎng)站是否存在重復(fù)內(nèi)容或URL?
·將所有內(nèi)容遷移到開(kāi)發(fā)站點(diǎn),盡可能保持不變;
·確保標(biāo)題標(biāo)簽和元描述被延續(xù),并且與當(dāng)前站點(diǎn)相同或更好;
·檢查頁(yè)面內(nèi)容、規(guī)范標(biāo)簽、內(nèi)部鏈接,H1s/H2s,IMG ALT標(biāo)簽的使用。
移動(dòng)站點(diǎn)特定任務(wù)
·在Screaming Frog中抓取移動(dòng)谷歌機(jī)器人,驗(yàn)證頁(yè)面之間的移動(dòng)對(duì)等:標(biāo)題、描述、標(biāo)題、內(nèi)容、鏈接、圖像、指令等;
·將meta =“viewport”標(biāo)簽履行到網(wǎng)站的
部分的。
Javascript站點(diǎn)特定任務(wù)
·可視化地審計(jì)所有主要頁(yè)面類型;
·審核缺少內(nèi)容的HTML源代碼;
·使用inspect元素檢查缺少的內(nèi)容;
·比較HTML源代碼和檢查元素是否矛盾;
·根據(jù)用戶交互來(lái)識(shí)別內(nèi)容。
AMP頁(yè)面特定任務(wù)
·每個(gè)非AMP頁(yè)面(即桌面、手機(jī))都應(yīng)該有一個(gè)指向相應(yīng)AMP URL的標(biāo)簽;
·每個(gè)AMP頁(yè)面應(yīng)該有一個(gè)rel= “canonical ”標(biāo)簽指向相應(yīng)的桌面頁(yè)面;
·任何沒(méi)有相應(yīng)桌面URL的AMP頁(yè)面應(yīng)該有一個(gè)自引用的規(guī)范標(biāo)記。
電子商務(wù)特定任務(wù)
·類別頁(yè)面是否包含指向產(chǎn)品的可索引鏈接;
·檢查分面導(dǎo)航、分頁(yè)以獲得最佳實(shí)踐;
·如果圖片鏈接出現(xiàn)在錨文本鏈接之前,是否使用了關(guān)鍵詞豐富的ALT文本。
WordPress特定任務(wù)
·使用Simple 301 Redirects Plugin重定向開(kāi)發(fā)站點(diǎn)WordPress中的URL;
·在WordPress站點(diǎn)和CMS(內(nèi)部管理系統(tǒng))上安裝Google Tag Manager Plugin (谷歌標(biāo)簽管理器插件)并進(jìn)行配置;
·設(shè)置Yoast WordPress SEO & Yoast Analytics插件;
·如果你使用像HubSpot這樣的CMS ,安裝并設(shè)置CMS插件;
·建立Yoast Analytics。
步驟1:站點(diǎn)抓取/分析檢查
在這個(gè)步驟中,你將檢查活動(dòng)站點(diǎn)和測(cè)試站點(diǎn)之間的匹配數(shù)據(jù):
1、驗(yàn)證301重定向都已正確實(shí)施;
2、抓取新站點(diǎn)以確定技術(shù)問(wèn)題和可訪問(wèn)性;;
3、確保新的活動(dòng)站點(diǎn)沒(méi)有被阻止、被抓取和索引
4、驗(yàn)證是否將“Nofollow”標(biāo)記添加到不希望索引的頁(yè)面。這些應(yīng)該在開(kāi)發(fā)站點(diǎn)上進(jìn)行標(biāo)識(shí),例如在分面導(dǎo)航鏈接上;
5、確保每個(gè)頁(yè)面上都有“index、follow”元標(biāo)記;
6、尋找不應(yīng)該出現(xiàn)的404頁(yè)面;
7、檢查內(nèi)部鏈接:查找斷開(kāi)的鏈接,以及指向開(kāi)發(fā)站點(diǎn)的鏈接;
8、驗(yàn)證規(guī)范標(biāo)簽的項(xiàng)目執(zhí)行;
9、檢查標(biāo)準(zhǔn)和重復(fù)URL;
10、檢查標(biāo)題標(biāo)簽(與舊數(shù)據(jù)匹配);
11、檢查元描述(與舊數(shù)據(jù)匹配);
12、檢查H1、H2使用情況(與舊數(shù)據(jù)匹配);
13、檢查IMG ALT屬性(與舊數(shù)據(jù)匹配);
14、檢查字?jǐn)?shù)(與舊數(shù)據(jù)匹配,解釋
標(biāo)簽內(nèi)的所有模板文本);
15、按頁(yè)面檢查內(nèi)部鏈接計(jì)數(shù)(與舊數(shù)據(jù)匹配,是否有關(guān)鍵頁(yè)面丟失鏈接)。
步驟2: Google Analytics(谷歌分析) / Search Console Checks(谷歌站長(zhǎng)工具)
現(xiàn)在你可以觀察谷歌為新站點(diǎn)注冊(cè)了哪些數(shù)據(jù):
1、確保其準(zhǔn)確性:驗(yàn)證所有頁(yè)面上的分析代碼,以及實(shí)施正確的代碼;
2、更新分析目標(biāo),檢查它們是否能夠正常工作;
3、使用網(wǎng)站啟動(dòng)日期對(duì)分析進(jìn)行注釋。
步驟3:網(wǎng)站速度檢查
1、觀察通過(guò)站點(diǎn)速度工具運(yùn)行幾個(gè)頁(yè)面,將舊站點(diǎn)和開(kāi)發(fā)站點(diǎn)上的站點(diǎn)速度進(jìn)行相比;
2、如果可以的話,做好改進(jìn)的記錄。
步驟4:其他任務(wù)
1、站點(diǎn)是否更改了服務(wù)器?確保沒(méi)有與服務(wù)器相關(guān)的問(wèn)題;
2、比較頂部登錄頁(yè)面,前后(標(biāo)題、元描述、頁(yè)眉、頁(yè)面內(nèi)容等);
3、驗(yàn)證404頁(yè)面是否返回404狀態(tài);
4、驗(yàn)證舊的XML站點(diǎn)地圖是否在新站點(diǎn)上,重新提交到Google Search Console (谷歌站長(zhǎng)工具)和 Bing Webmaster Tools(必應(yīng)網(wǎng)站管理員工具);
5、如果域正在更改,請(qǐng)?jiān)贕SC中聲明新的域變體并提交地址更改請(qǐng)求。
1、發(fā)布后一周
·監(jiān)控GSC谷歌站長(zhǎng)工具(抓取統(tǒng)計(jì)數(shù)據(jù)、排名、流量、索引頁(yè)面等);
·檢查GSC是否有新的索引頁(yè)面(并檢查任何沒(méi)有索引的頁(yè)面);
·檢查舊的GSC配置文件,以確保舊頁(yè)面被取消索引;
·保留舊的XML站點(diǎn)地圖,讓谷歌重新抓取。
2、發(fā)布后2 - 3周內(nèi)
·監(jiān)控谷歌站長(zhǎng)工具(抓取統(tǒng)計(jì)數(shù)據(jù)、排名、流量、索引頁(yè)面等);
·刪除舊的XML站點(diǎn)地圖,用新的XML站點(diǎn)地圖替換它們;
·檢查sitemap.xml文件,是否有正確的url(無(wú)多余的URL、沒(méi)有Dev URL等);
·提交新的XML站點(diǎn)地圖到谷歌站長(zhǎng)工具&必應(yīng)網(wǎng)站管理員工具。
3、發(fā)布后一個(gè)月
·監(jiān)控谷歌站長(zhǎng)工具(抓取統(tǒng)計(jì)數(shù)據(jù)、排名、流量、索引頁(yè)面等);
·檢查流量損失分析,觀察哪些頁(yè)面丟失了流量以及原因。
4、發(fā)布后2個(gè)月
·繼續(xù)監(jiān)控谷歌站長(zhǎng)工具(抓取統(tǒng)計(jì)數(shù)據(jù)、排名、流量、索引頁(yè)面等);
·大多數(shù)遷移通常會(huì)在啟動(dòng)后出現(xiàn)流量的下降和上升。也就是說(shuō),每個(gè)地點(diǎn)和遷移都是不同的,所以實(shí)際的影響很難預(yù)測(cè);
· 較好的辦法就是遵循這個(gè)過(guò)程。這樣做可以確保新站點(diǎn)的數(shù)據(jù)仍然被谷歌索引,從而對(duì)潛在客戶可見(jiàn)。
(編譯/雨果網(wǎng) 宋淑湲)
【特別聲明】未經(jīng)許可同意,任何個(gè)人或組織不得復(fù)制、轉(zhuǎn)載、或以其他方式使用本網(wǎng)站內(nèi)容。轉(zhuǎn)載請(qǐng)聯(lián)系:editor@cifnews.com
eta 版的 Execute Program 是用 Ruby 和 JavaScript 編寫(xiě)的。之后,我們分幾步將整個(gè)應(yīng)用完全移植到了 TypeScript 上。本文介紹的是移植的第一步,也就是前端的部分。
在 Execute Program 的原始 JavaScript 前端中,我經(jīng)常會(huì)犯一些小錯(cuò)誤。例如,我會(huì)將錯(cuò)誤的 prop 名稱傳遞給 React 組件,或者遺漏某個(gè) prop,抑或傳遞錯(cuò)誤的數(shù)據(jù)類型。(Prop 是作為參數(shù)發(fā)送到 React 組件的數(shù)據(jù)。組件將一些 props 傳遞給自己的某個(gè)子組件,以此類推,這是很常見(jiàn)的。)
對(duì)于像 JavaScript 和 Ruby 這樣的動(dòng)態(tài)語(yǔ)言來(lái)說(shuō),這不是個(gè)小問(wèn)題。過(guò)去 15 年來(lái)我一直在學(xué)習(xí)該如何應(yīng)對(duì)這種錯(cuò)誤問(wèn)題。我在之前談?wù)摰氖?2011 年代的情況,其中討論的緩解措施確實(shí)有些用途,但它們無(wú)法隨著系統(tǒng)的發(fā)展順利地?cái)U(kuò)展下去,而且我們忘掉它們時(shí)也沒(méi)有安全網(wǎng)可用。
我覺(jué)得 15 年時(shí)間已經(jīng)夠長(zhǎng)了。我想回到靜態(tài)類型系統(tǒng)的懷抱,畢竟這種系統(tǒng)中根本不會(huì)出現(xiàn)這類錯(cuò)誤。彼時(shí)我們有幾個(gè)選項(xiàng):Elm、Reason、Flow、TypeScript 和 PureScript。(這里舉了一部分例子。)最后我決定使用 TypeScript 是因?yàn)椋?/p>
在 2018 年 10 月,我們用了大約兩天時(shí)間將前端 JavaScript 代碼移植到了 TypeScript。下面的圖表顯示了在移植前和移植后每種語(yǔ)言擁有的代碼量。
當(dāng)時(shí)我們還是 pre-beta 版本,所以系統(tǒng)還很小,只有大約 6,000 行。這張圖上沒(méi)有涉及移植后的情況;我們將在以后的文章中具體介紹相關(guān)內(nèi)容。
在這次移植之后,React prop 問(wèn)題消失了。下面我們會(huì)看幾個(gè)示例,首先是一個(gè)簡(jiǎn)單的例子。以下是渲染“Continue”按鈕的代碼,這個(gè)按鈕出現(xiàn)在我們課程的每個(gè)文本段落之后:
復(fù)制代碼
<Button autofocus={true} icon="arrowRight" onClick={continue} primary> Continue</Button>
這個(gè) Button 組件的 props 的類型如下所示。當(dāng)讀取諸如 autofocus?: boolean 之類的屬性類型時(shí):“autofocus”是屬性的名稱;“?”表示它是可選的;“:”將屬性名稱與其類型分開(kāi);而“boolean”是類型。最后一個(gè)屬性類型 onClick 表示“一個(gè)不帶參數(shù)且不返回任何內(nèi)容的函數(shù)”。如果你不熟悉 TypeScript 的函數(shù)類型語(yǔ)法,可以在我們的課程中全面了解 TypeScript 的函數(shù)類型。
復(fù)制代碼
type ButtonProps = { autofocus?: boolean icon?: IconName primary?: boolean onClick: () => void}
如果將“autofocus”prop 從 true 更改為 1,會(huì)發(fā)生什么?現(xiàn)在,我們?cè)陬愋拖到y(tǒng)期望一個(gè)布爾值的地方傳遞了一個(gè)數(shù)字值。不到一秒鐘后,編譯器將在下面顯示錯(cuò)誤。(這里刪除了一些不相關(guān)的細(xì)節(jié);本系列文章中所有涉及到錯(cuò)誤的地方都會(huì)這樣處理。)
復(fù)制代碼
src/client/components/explanation.tsx(13,27): error: Type 'number' is not assignable to type 'boolean | undefined'.
有害代碼在 vim 中也變成了紅色。修好它后,紅色消失了。解決錯(cuò)誤只需要幾秒鐘。在 Ruby 或 JavaScript 中,我可能會(huì)花幾分鐘的時(shí)間手動(dòng)測(cè)試應(yīng)用程序,并反復(fù)瀏覽它的狀態(tài)才能知道到底發(fā)生了什么事情。我也可以依靠自動(dòng)化測(cè)試,但是我們?cè)诹硪黄恼轮薪榻B了測(cè)試 vs 類型的問(wèn)題。
這個(gè)整數(shù)到布爾的更改是對(duì)類型系統(tǒng)的一次簡(jiǎn)單而低風(fēng)險(xiǎn)的測(cè)試。Button 的 icon 屬性顯示了更高級(jí)的用法。下面還是 Button 調(diào)用:
復(fù)制代碼
<Button autofocus={true} icon="arrowRight" onClick={continue} primary> Continue</Button>
看起來(lái) icon prop 只是一個(gè)字符串:“arrowRight”。在運(yùn)行時(shí),在已編譯的 JavaScript 代碼中,它將是一個(gè)字符串。但是在上面顯示的 ButtonProps 類型中,我們將其定義為 IconName,后者是在其他地方定義的。在查看其定義之前,讓我們先看看這個(gè)類型的作用。假設(shè)我們將“icon”prop 更改為“banana”。我們實(shí)際上沒(méi)有名為“banana”的圖標(biāo)。
復(fù)制代碼
<Button autofocus={true} icon="banana" onClick={continue} primary> Continue</Button>
不到一秒鐘后,TypeScript 編譯器拒絕了這一更改:
復(fù)制代碼
src/client/components/explanation.tsx(13,44): error: Type '"banana"' is not assignable to type '"menu" | "arrowDown" | "arrowLeft" | ... 21 more ... | undefined'.
編譯器說(shuō)“icon”不能是任意字符串。它必須是我們定義為 icon 名稱的 24 個(gè)字符串之一。編譯器將拒絕任何使我們引用不存在圖標(biāo)的更改;這不是有效的程序,甚至無(wú)法開(kāi)始執(zhí)行。
有多種方法可以實(shí)現(xiàn) IconName 類型。一種是編寫(xiě)一種類型,該類型顯式列出所有可能的 icon 名稱。然后,我們必須使 icon 名稱與其在磁盤(pán)上的圖像文件保持同步。這種類型可能是這樣的:
復(fù)制代碼
type IconName = "menu" | "arrowDown" | "arrowLeft" | "arrowRight" | ...
翻譯成中文:“這里會(huì)靜態(tài)地保證 IconName 類型的一個(gè)值是此處指定的字符串之一,但不能是其他任何字符串?!保ㄟ@個(gè)類型是我們兩堂課程涵蓋的兩個(gè)主題的組合:字面量類型和類型聯(lián)合)
我們的 IconName 未被定義為字面量類型的簡(jiǎn)單聯(lián)合。讓圖標(biāo)名稱列表與文件列表保持同步是很無(wú)聊的工作,我們可以讓計(jì)算機(jī)來(lái)完成它!相反,我們的 icon.tsx 文件如下所示:
復(fù)制代碼
export const icons = { arrowDown: { label: "Down Arrow", data() { return <path ... /> } }, arrowLeft: { label: "Left Arrow", data() { return <path ... /> } }, ...}
實(shí)際的 SVG < path/> 標(biāo)簽就在源代碼中,在以 icon 名稱為鍵的對(duì)象中。(也可以在不將 SVG 內(nèi)聯(lián)到源文件中的情況下執(zhí)行此操作。例如,我們可以使用一些 Webpack 技巧將圖像保存在它們自己的文件中,但仍然可以確保列表中的每個(gè)圖標(biāo)也都存在于磁盤(pán)上。到目前為止,這種簡(jiǎn)單的解決方案對(duì)我們來(lái)說(shuō)是很好用的。)
通過(guò)這種方式定義 icon 后,我們可以使用一行代碼自動(dòng)提取其名稱的聯(lián)合類型(union type):
復(fù)制代碼
export type IconName = keyof typeof icons
(這里的意思是,你可以認(rèn)為該類型表示“每當(dāng)某物的類型為”IconName”時(shí),它必須是與 icons 對(duì)象的鍵之一匹配的字符串。)
這樣就搞定了;并不需要其他類型層面的工作。剩下的代碼只是一個(gè)簡(jiǎn)單的 Icon React 組件,它在列表中查找圖標(biāo)并返回其 SVG 路徑。這個(gè)函數(shù)中沒(méi)有明確的 TypeScript 類型。它看起來(lái)像是純粹的 JavaScript 代碼,但它也經(jīng)過(guò)了類型檢查。這是一個(gè)最小版本,其中刪除了所有無(wú)關(guān)的細(xì)節(jié):
復(fù)制代碼
export function Icon(props: { name: IconName}) { return <svg> {icons[props.name].data()} </svg>}
現(xiàn)在,我們可以將 SVG 標(biāo)簽放入這個(gè)源文件中,并將新 icon 拖放到“icons”列表中。當(dāng)我們這樣做時(shí),這個(gè) icon 就可以在 Button 組件,以及系統(tǒng)內(nèi)接受 icon 名稱的其他任何部分中使用。如果我們從列表中刪除一個(gè) icon,則系統(tǒng)中引用該 icon 的所有部分都將立即無(wú)法編譯,從而確保沒(méi)有過(guò)時(shí)的 icon 引用在運(yùn)行時(shí)導(dǎo)致錯(cuò)誤。
這些示例按照靜態(tài)類型標(biāo)準(zhǔn)來(lái)說(shuō)是很簡(jiǎn)單的,但我認(rèn)為它們證明了 Web 應(yīng)用程序中有多少可以輕松實(shí)現(xiàn)的改進(jìn)之處。一個(gè)應(yīng)用程序中的大多數(shù)代碼都不涉及高級(jí)類型系統(tǒng)功能;多數(shù)需求僅僅是“確保我們傳遞正確的 props”和“確保我們的圖標(biāo)確實(shí)存在”之類的簡(jiǎn)單事情。
我們?cè)谡麄€(gè)系統(tǒng)中都做了這種事情。其他的一些示例:
諸如此類的問(wèn)題經(jīng)常會(huì)出現(xiàn)在編程工作中,尤其是在動(dòng)態(tài)語(yǔ)言中非常常見(jiàn);但我們無(wú)需編寫(xiě)任何自動(dòng)測(cè)試,也用不著什么手動(dòng)測(cè)試,就可以從靜態(tài)上避免這些問(wèn)題。有些問(wèn)題解決起來(lái)需要費(fèi)些功夫。我們的 API 路由器驗(yàn)證寫(xiě)起來(lái)很麻煩。但是寫(xiě)多了就順手了。上面的單行“IconName”類型實(shí)際上是問(wèn)題的完整解決方案。如果將其復(fù)制到 TypeScript 文件中,它就能起作用。
將我們的前端代碼移植到 TypeScript 僅僅是個(gè)開(kāi)始。那之后,我們又將后端從 Ruby 移植到了 TypeScript,然后在移植后的 9 個(gè)月內(nèi)對(duì)其進(jìn)行了擴(kuò)展和維護(hù)。
oogle Docs宣布將會(huì)把HTML遷移到基于Canvas渲染,這一消息的出現(xiàn)再次把幾年前隨HTML5誕生的標(biāo)簽重新推到了人們視線之中。Canvas在剛推出時(shí)主打的優(yōu)勢(shì)就是更快的渲染速度,堪稱HTML屆的“小飛人”,刷新了人們對(duì)Web頁(yè)面元素繪制速度的印象。但Canvas的優(yōu)勢(shì)僅限于此嗎?
(圖片來(lái)源于網(wǎng)絡(luò))
Canvas是HTML5時(shí)代引入的“新”標(biāo)簽。與很多標(biāo)簽不同,Canvas不具有自己的行為,只將一組API 展現(xiàn)給客戶端 JavaScript ,讓開(kāi)發(fā)者使用腳本把想繪制的東西畫(huà)到一張畫(huà)布上。
在HTML5之前,人們通常使用SVG來(lái)在頁(yè)面上繪制出圖形。SVG使用XML來(lái)定義圖形,就像使用HTML標(biāo)簽和樣式定義DIV一樣,我們也可以將一個(gè)空白的DIV想象為長(zhǎng)方形的SVG,兩者的設(shè)計(jì)思想是相通的,SVG的本質(zhì)就是一個(gè)DOM元素。而Canvas則不同,Canvas提供的是 JavaScript 的繪圖 API,而不是像 SVG那樣使用XML 描述繪圖,通過(guò)JavaScript API直接完成繪制,比起修改XML來(lái)說(shuō)要更簡(jiǎn)便、更直接。
除了定義的方式不同,Canvas和DOM(當(dāng)然也包含SVG)的差異更多的體現(xiàn)在瀏覽器的渲染方式上。
瀏覽器在做頁(yè)面渲染時(shí),Dom元素是作為矢量圖進(jìn)行渲染的。每一個(gè)元素的邊距都需要單獨(dú)處理,瀏覽器需要將它們?nèi)继幚沓上袼夭拍茌敵龅狡聊簧?,?jì)算量十分龐大。當(dāng)頁(yè)面上內(nèi)容非常多,存在大量DOM元素的時(shí)候,這些內(nèi)容的渲染速度就會(huì)變得很慢。
而Canvas與DOM的區(qū)別則是Canvas的本質(zhì)就是一張位圖,類似img標(biāo)簽,或者一個(gè)div加了一張背景圖(background-image)。所以,DOM那種矢量圖在渲染中存在的問(wèn)題換到Canvas身上就完全不同了。在渲染Canvas時(shí),瀏覽器只需要在JavaScript引擎中執(zhí)行繪制邏輯,在內(nèi)存中構(gòu)建出畫(huà)布,然后遍歷整個(gè)畫(huà)布里所有像素點(diǎn)的顏色,直接輸出到屏幕就可以了。不管Canvas里面的元素有多少個(gè),瀏覽器在渲染階段也僅需要處理一張畫(huà)布。
然而這樣更加強(qiáng)大的功能,不可避免的讓使用canvas渲染有很高的門(mén)檻。Google Docs在構(gòu)建Canvas的過(guò)程中重新定義了往常已經(jīng)被人們所熟悉的內(nèi)容,例如精確定位、文本選擇、拼寫(xiě)檢查、重畫(huà)調(diào)優(yōu)等。為什么更多開(kāi)發(fā)者還是選擇了接納Canvas這個(gè)門(mén)檻更高的技術(shù)路線呢?這就得回到Canvas的最大優(yōu)勢(shì):渲染性能。
這里的渲染是指瀏覽器將頁(yè)面的代碼呈現(xiàn)為屏幕上內(nèi)容的過(guò)程。Canvas和Dom的渲染模式完全不同,搞清楚這個(gè)差異對(duì)理解Canvas的性能優(yōu)勢(shì)至關(guān)重要。
Dom:駐留模式
駐留模式(Retained Mode)是Dom在瀏覽器中的渲染模式。下圖粗略展示了這一過(guò)程的工作流程。
DOM的核心是標(biāo)簽,一種文本標(biāo)記型語(yǔ)言,多樣性很強(qiáng)且多個(gè)標(biāo)簽之間存在各種關(guān)聯(lián)(如在同一個(gè)DIV下設(shè)置為float的子DIV)。瀏覽器為了更好的處理這些DOM元素,減少對(duì)繪制API的調(diào)用,就設(shè)計(jì)了一套將中間結(jié)果存放于內(nèi)存的“駐留模式”。首先,瀏覽器會(huì)將解析DOM相關(guān)的全部?jī)?nèi)容(包含HTML標(biāo)簽、樣式和JavaScript),將其轉(zhuǎn)化為場(chǎng)景(scene)和模型(model)存儲(chǔ)到內(nèi)存中,然后再調(diào)用系統(tǒng)的繪制API(如Windows程序員熟悉的GDI/GDI+),把這些中間產(chǎn)物繪制到屏幕。
駐留模式通過(guò)場(chǎng)景和模型緩存減少了對(duì)繪制API的調(diào)用頻次,將性能壓力轉(zhuǎn)移到場(chǎng)景和模型生成階段,即瀏覽器需要根據(jù)DOM上下文和BOM中的尺寸數(shù)據(jù),“自行判斷”每一個(gè)元素的繪制結(jié)果。
Canvas:快速模式
Canvas采用了和DOM不同的快速模式(Immediate Mode),讓我們先來(lái)看看快速模式是如工作的:
與駐留模式相比,快速模式將場(chǎng)景和模型的生成從瀏覽器移交給了開(kāi)發(fā)者。開(kāi)發(fā)者在設(shè)計(jì)頁(yè)面時(shí),就通過(guò)Canvas的JavaScript API定義了畫(huà)布內(nèi)所有元素的繪制方式。瀏覽器只需要簡(jiǎn)單的執(zhí)行這些腳本即可,而不需要像渲染DOM一樣逐個(gè)處理子元素了。
在快速模式中,頁(yè)面的繪制性能得到了大幅提升。但開(kāi)發(fā)者不僅需要指定什么需要畫(huà),還要?jiǎng)?chuàng)建和維護(hù)一個(gè)模型。此外,開(kāi)發(fā)者還需要管理好當(dāng)前場(chǎng)景重繪時(shí)帶來(lái)的改變,以及響應(yīng)用戶的點(diǎn)擊或輸入操作等。
上面介紹的兩種不同的模式直接造成了Dom和Canvas的性能差異。對(duì)于使用快速模式渲染的Canvas而言,瀏覽器的每次重繪都是基于代碼的,不存在能讓處理流程變慢的多層解析,所以它真的很快。除了快之外,Canvas的靈活性也大大超出DOM。我們可以通過(guò)代碼精確的控制如何、何時(shí)繪制出我們想要的效果。
在資源消耗上,DOM的駐留模式意味著場(chǎng)景中每增加一點(diǎn)東西就需要額外消耗一些內(nèi)存,而Canvas并沒(méi)有這個(gè)問(wèn)題。這個(gè)差異會(huì)隨著頁(yè)面元素的數(shù)量增多而愈加明顯。以B端的企業(yè)應(yīng)用場(chǎng)景為例,表單那種數(shù)據(jù)量比較小的場(chǎng)景,不同渲染模式帶來(lái)的效果差異并不明顯;但在工業(yè)制造、金融財(cái)會(huì)等類Excel電子表格操作的場(chǎng)景下,單元格數(shù)量動(dòng)輒便是上百萬(wàn)(5萬(wàn)行x 20列)甚至上億個(gè),瀏覽器需要對(duì)表格所有單元格本身內(nèi)容進(jìn)行渲染,同時(shí)還涉及到豐富的數(shù)據(jù)處理,情況就完全不同了。
(Web頁(yè)面上的電子表格,包含1百萬(wàn)個(gè)單元格)
在Canvas出現(xiàn)之前,在前端渲染表格時(shí)只能通過(guò)構(gòu)建復(fù)雜的DOM來(lái)實(shí)現(xiàn)。這種方式下,瀏覽器的性能成為了Web應(yīng)用瓶頸,讓很多開(kāi)發(fā)者放棄了在瀏覽器上實(shí)現(xiàn)電子表格的想法。
在Canvas出現(xiàn)后,快速模式帶來(lái)的性能優(yōu)勢(shì)無(wú)疑是一個(gè)巨大的亮點(diǎn),大量、復(fù)雜的DOM渲染處理帶來(lái)的性能問(wèn)題終于有了解決途徑。
回到電子表格的應(yīng)用場(chǎng)景,業(yè)內(nèi)已經(jīng)出現(xiàn)了使用Canvas繪制畫(huà)布的表格組件,這類組件在渲染數(shù)據(jù)層時(shí)不僅無(wú)需重復(fù)創(chuàng)建和銷(xiāo)毀DOM元素,在畫(huà)布的繪制過(guò)程中,也比Dom元素渲染的限制更少。除了表格之外,Canvas也為數(shù)字孿生可視化大屏、頁(yè)面游戲等場(chǎng)景帶來(lái)了變革。
(數(shù)字孿生大屏,精確控制各種形狀、樣式)
總結(jié)一下,在渲染模式上,Canvas站在了DOM的對(duì)面,瀏覽器對(duì)其內(nèi)容一無(wú)所知,一切渲染的權(quán)利回到了開(kāi)發(fā)者的手上,這個(gè)改變帶來(lái)了顯著的性能優(yōu)勢(shì)。此外,我們可以使用Canvas繪制種類更為豐富的UI元素,如線形、特殊圖形等,通過(guò)畫(huà)法邏輯,還可以實(shí)現(xiàn)更加精準(zhǔn)的UI界面渲染,解決了瀏覽器差異造成的樣式誤差,讓更多應(yīng)用場(chǎng)景可以順利遷移到Web平臺(tái)上來(lái)。
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。