社區(qū)精選|腳本執(zhí)行順序引發(fā)的慘案
今天小編為大家?guī)淼氖巧鐓^(qū)作者 記得要微笑 的文章,讓我們一起來看看這場(chǎng)腳本執(zhí)行順序引發(fā)的慘案??
SRE(系統(tǒng)可靠性工程師)進(jìn)行處理。令人困惑的是,SRE在訪問生產(chǎn)環(huán)境的"查看報(bào)價(jià)頁面"時(shí)發(fā)現(xiàn)一切正常。
SRE向用戶申請(qǐng)了遠(yuǎn)程操作權(quán)限。在遠(yuǎn)程操作期間,并沒有發(fā)現(xiàn)瀏覽器控制臺(tái)中存在錯(cuò)誤日志,所有頁面所依賴的JavaScript和CSS腳本都能夠正常加載,但加載完成后并沒有執(zhí)行掛載頁面模塊的操作。因此,初步猜測(cè)問題可能出現(xiàn)在頁面路由加載方面,導(dǎo)致頁面無法正常掛載。
react-router模塊進(jìn)行路由配置的部分代碼,同時(shí)在路由加載過程中進(jìn)行數(shù)據(jù)采集:
component: Loadable({loader: () => import('@/pages/inquiry-detail-by-brand').then((comp) => {/** 頁面訪問 PV、UV */debugger;if ('cassSensorsTrack' in window) {(window as any).cassSensorsTrack({eventName: BURY_EVENT_NAME.QUOTATION_RESULT_PAGE_VIEW_CLICK,desc: '頁面瀏覽',eventType: 'click',eventData: '',});}return comp;}),loading: Loading,})
懷疑頁面組件模塊comp沒有正確掛載到頁面上,在then回調(diào)函數(shù)中添加斷點(diǎn)來驗(yàn)證自己的猜想。

經(jīng)過調(diào)試,發(fā)現(xiàn)問題是在腳本執(zhí)行時(shí),cassSensors 對(duì)象未定義,導(dǎo)致無法調(diào)用 track 方法。此外,外部代碼沒有包含異常處理的 try...catch 塊。然而,在使用 Loadable 組件時(shí),它內(nèi)部捕獲了該異常,并渲染了空內(nèi)容。

// 加載函數(shù)function load(loader) {var promise = loader();var state = {loading: true,loaded: null,error: null};state.promise = promise.then(function (loaded) {state.loading = false;state.loaded = loaded;return loaded;}).catch(function (err) {// 捕獲異常state.loading = false;state.error = err;throw err;});return state;}// renderLoadableComponent.prototype.render = function render() {if (this.state.loading || this.state.error) {return React.createElement(opts.loading, {isLoading: this.state.loading,pastDelay: this.state.pastDelay,timedOut: this.state.timedOut,error: this.state.error,retry: this.retry});} else if (this.state.loaded) {return opts.render(this.state.loaded, this.props);} else {return null;}};
為什么在加載頁面組件腳本后獲取不到 cassSensors 變量呢?

注:上述腳本加載順序是模擬出來的場(chǎng)景,跟實(shí)際腳本加載順序一致
不難發(fā)現(xiàn)問題是由于:
3.72881c2b.chunk.js 和 4.e6995327.chunk.js 在 sensorsdata1.19.4.min.js 之前加載和執(zhí)行,導(dǎo)致在執(zhí)行 .then 回調(diào)時(shí)無法訪問到 cassSensors 變量。
這是因?yàn)椋?/span>
cassSensors 是由 sensorsdata1.19.4.min.js 在全局作用域中注入的,而在回調(diào)執(zhí)行時(shí)它尚未定義,從而導(dǎo)致異常。
cassSensors,可以采用以下優(yōu)化方案。在異步加載完成之前,先給出一個(gè)結(jié)構(gòu)變量定義,讓應(yīng)用方調(diào)用不會(huì)報(bào)錯(cuò)。同時(shí),可以在頁面腳本中創(chuàng)建一個(gè)變量來緩存需要采集的數(shù)據(jù),等待腳本加載完成后再進(jìn)行上報(bào)操作。
// cassSensors.jsvar dataCache = [];// 在異步腳本腳本完之前先給出結(jié)構(gòu)變量定義,讓調(diào)用方不會(huì)執(zhí)行報(bào)錯(cuò)if (!"cassSensors" in window) {window.cassSensors = {track: function() {},// ...}}// 異步腳本加載完成后,重新拋出變量,并且上報(bào)緩存中的數(shù)據(jù)script.onload = fucntion() {window.cassSensors = window['sensorsDataAnalytic201505'];window.cassSensors.init();// ...if (dataCache.length) {dataCache.forEach(function(dc) {window.cassSensors.track(dc); // 上報(bào)});dataCache = [];}}
cassSensors,避免了報(bào)錯(cuò)。同時(shí),通過緩存數(shù)據(jù)并在加載完成后進(jìn)行上報(bào),確保頁面腳本能夠正確獲取到cassSensors變量,并且不會(huì)因?yàn)榧虞d順序問題而導(dǎo)致異常。
npm包的形式進(jìn)行發(fā)版、按需引入和構(gòu)建打包到業(yè)務(wù)代碼中。
Fiddler 反向代理來延遲加載 sensorsdata1.19.4.min.js 文件,以使頁面腳本的執(zhí)行在 sensorsdata1.19.4.min.js 之前。
Fiddler 破解版的同學(xué)可以使用 Nginx 來模擬該場(chǎng)景,并通過第三方的 echo-nginx-module 模塊進(jìn)行配置,以實(shí)現(xiàn)延遲響應(yīng)的反向代理。具體安裝步驟可以參考:https://www.cnblogs.com/52fhy/p/10166333.html
http {listen 8081;server_name localhost;# 其他配置項(xiàng)...server {# 其他 server 配置項(xiàng)...location /proxy/ {rewrite ^/proxy/(.*)$ /$1 break;proxy_pass https://mstatic.cassmall.com;# 設(shè)置頭部內(nèi)容編碼類型,防止返回亂碼proxy_set_header Accept-Encoding "";proxy_set_header Accept-Language $http_accept_language;proxy_set_header Content-Type "text/javascript; charset=utf-8";}location /delay {# prelight requestif ($request_method = 'OPTIONS') {add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';add_header 'Access-Control-Max-Age' 1728000;add_header 'Content-Type' 'text/plain; charset=utf-8';add_header 'Content-Length' 0;return 204;}# 設(shè)置反向代理目標(biāo)服務(wù)器# proxy_pass http://your_backend_server;echo_location /proxy/$uri;# 設(shè)置延遲時(shí)間為 5 秒鐘set $delay 5;# 在代理響應(yīng)之前延遲 5 秒鐘echo_sleep $delay;}}}
echo_sleep 與 proxy_pass 配置會(huì)有沖突,兩者同時(shí)配置,只有一個(gè)會(huì)生效,所以此處使用 echo_location。
往期推薦
社區(qū)精選|“奇怪”的 Axios 攔截器
社區(qū)精選|納尼!CSS 也能實(shí)現(xiàn)碰撞檢測(cè)?
社區(qū)精選|【NestJS 系列】DI 依賴注入與 IOC 控制反轉(zhuǎn)
