摘要:前段時(shí)間重構(gòu)一個(gè)頁面,頁面中存在通過第三方代碼插入的動(dòng)態(tài)廣告正常的產(chǎn)品需求,上線后發(fā)現(xiàn)第三方的廣告資源存在重復(fù)請求的問題。所以,同一個(gè)請求會(huì)觸發(fā)兩次的原因頁面加載時(shí)渲染元素會(huì)觸發(fā)第一次請求,執(zhí)行代碼導(dǎo)致重新渲染觸發(fā)第二次請求。
前段時(shí)間重構(gòu)一個(gè)頁面,頁面中存在通過第三方JavaScript代碼插入的動(dòng)態(tài)廣告(正常的產(chǎn)品需求),上線后發(fā)現(xiàn)第三方的廣告資源存在重復(fù)請求的問題。由于控制廣告插入的JavaScript代碼由第三方提供,我們只負(fù)責(zé)按照他們要求的方式引入即可,所以對JavaScript代碼內(nèi)容并不了解,在這種情況下開始了艱難的排查過程。雖困難重重,但最終還是找到了原因,在此過程中有些收獲,現(xiàn)將排查過程抽象如下:
注:以下過程和截圖皆在Chrome瀏覽器中進(jìn)行。
一、代碼代碼大意:頁面上先渲染3個(gè)iframe(目前頁面插入廣告仍然以iframe作為主要實(shí)現(xiàn)形式),然后在最后一個(gè)iframe后面追加一個(gè)p元素
二、現(xiàn)象 1.頁面:渲染正常 2.Network:存在重復(fù)的異常請求(Status是canceled) 三、排查過程 1.重復(fù)請求從何而來?既然是解決重復(fù)請求的問題,那么重復(fù)請求從何而來是我們要解決的第一問題。
由于請求是從第三方的JavaScript代碼中發(fā)出的,去讀第三方壓縮后的JavaScript代碼更像無頭蒼蠅。整個(gè)過程就像在圍城之外徘徊,心急如焚。后來靜下心來發(fā)現(xiàn)Chrome的devtools中一個(gè)很關(guān)鍵的排查助力神器:Network下的Initiator
此列是什么意思呢?通俗地說就是觸發(fā)請求的位置。
通過對比發(fā)現(xiàn),同一個(gè)重復(fù)的請求發(fā)起的位置并不相同,以/iframe-1為例:
點(diǎn)擊第一個(gè)請求的Initiator,跳轉(zhuǎn)的位置(標(biāo)黃位置):
點(diǎn)擊第二個(gè)請求的Initiator,跳轉(zhuǎn)的位置(標(biāo)黃位置):
通過觀察可以發(fā)現(xiàn),第一個(gè)/iframe-1請求是由于正常渲染iframe元素自動(dòng)觸發(fā)的,第二個(gè)/iframe-1請求是在執(zhí)行JavaScript代碼(作用拼接DOM節(jié)點(diǎn))時(shí)觸發(fā)的,然而對于觸發(fā)第二個(gè)/iframe-1請求的那行JavaScript代碼,其真實(shí)意圖僅僅是拼接一個(gè)p元素而已,并不期望其他額外的事情(比如觸發(fā)新的請求)發(fā)生。另外,對于/iframe-2和/iframe-3的第二次請求的觸發(fā)點(diǎn)都是那段拼接DOM節(jié)點(diǎn)的JavaScript代碼,至此,產(chǎn)生問題的罪魁禍?zhǔn)滓呀?jīng)浮出水面,接下來我們分析下產(chǎn)生重復(fù)請求的原因。
2.為什么會(huì)重復(fù)請求?產(chǎn)生重復(fù)請求的JavaScript代碼
document.getElementById("container").innerHTML += "上面是iframe
";
翻譯成:
document.getElementById("container").innerHTML = document.getElementById("container").innerHTML + "上面是iframe
";
意思就明了多了:先獲取id為container的div元素的所有內(nèi)部HTML,將其拼接p元素后,再賦值給container的innerHTML。
這個(gè)過程會(huì)導(dǎo)致iframe元素的重新渲染,也就會(huì)引發(fā)iframe對應(yīng)的請求重新觸發(fā)。
所以,同一個(gè)請求會(huì)觸發(fā)兩次的原因:頁面加載時(shí)渲染iframe元素會(huì)觸發(fā)第一次請求,執(zhí)行JavaScript代碼導(dǎo)致iframe重新渲染觸發(fā)第二次請求。
找到了問題的原因,解決問題的辦法也就水到渠成了,將
document.getElementById("container").innerHTML += "上面是iframe
";
改為:
var div = document.createElement("div"); var text = document.createTextNode("廣告"); div.appendChild(text); document.getElementById("container").appendChild(div);
問題解決了,不過,還有一個(gè)疑問:為什么渲染iframe產(chǎn)生的第一個(gè)請求的狀態(tài)是canceled?
3.為什么重復(fù)的請求的Status是canceled?首先Status是canceled代表什么意思呢?
從其字面意思理解,代表此請求被取消了,即此請求在發(fā)給服務(wù)器端之前就被瀏覽器取消了,也就是說此請求根本就沒有從瀏覽器發(fā)出去,更不可能到達(dá)服務(wù)器,所以狀態(tài)是canceled而不是HTTP狀態(tài)碼也就不難理解了。
那第一次的請求為什么會(huì)被瀏覽器取消呢?
用關(guān)鍵詞“chrome cancel request”谷歌了一下,在stack overflow上找到了一個(gè)比較全面的解答,截圖如下:
其中紅色標(biāo)注即為我們要尋找的答案。
根據(jù)截圖大概梳理一下,Chrome瀏覽器會(huì)取消請求的幾種場景:
觸發(fā)請求的DOM元素被刪除了(比如img元素還沒有加載完就被刪除了)
做了一些不必要的數(shù)據(jù)加載(比如開始加載iframe后改變其src或重寫其內(nèi)容)
大量的請求指向同一個(gè)服務(wù)器,并且前面請求的網(wǎng)絡(luò)問題表明后續(xù)的請求也走不通(DNS查詢錯(cuò)誤,前面的請求報(bào)400)
至此,整個(gè)過程中的疑問點(diǎn)一一解開了。
四、總結(jié)現(xiàn)在再回顧此bug,產(chǎn)生的原因并不高深,但整個(gè)排查過程確實(shí)值得總結(jié)。小結(jié)一下:
1.對于第三方庫報(bào)錯(cuò),切莫妄圖通過通讀并熟悉整個(gè)庫后解決問題,通讀代碼只會(huì)浪費(fèi)解決問題的時(shí)間,弄明白調(diào)用關(guān)系才是王道
2.Chrome開發(fā)者工具中的Network > Initiator代表請求是從哪里觸發(fā)的,對于定位請求非常有用,尤其是對于一些第三方庫中發(fā)出的請求
3.請求狀態(tài)為canceled,表示請求被瀏覽器取消了,并沒有從瀏覽器發(fā)出去,更不可能進(jìn)到服務(wù)器
4.Chrome瀏覽器取消請求的幾種情景,見上圖
5.element.innerHTML += HTMLStr 表示將原有的子節(jié)點(diǎn)和新的節(jié)點(diǎn)拼接后再重新賦值,會(huì)導(dǎo)致節(jié)點(diǎn)元素重新渲染,節(jié)點(diǎn)內(nèi)容中含有iframe時(shí)慎用
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/98630.html
摘要:前段時(shí)間重構(gòu)一個(gè)頁面,頁面中存在通過第三方代碼插入的動(dòng)態(tài)廣告正常的產(chǎn)品需求,上線后發(fā)現(xiàn)第三方的廣告資源存在重復(fù)請求的問題。所以,同一個(gè)請求會(huì)觸發(fā)兩次的原因頁面加載時(shí)渲染元素會(huì)觸發(fā)第一次請求,執(zhí)行代碼導(dǎo)致重新渲染觸發(fā)第二次請求。 前段時(shí)間重構(gòu)一個(gè)頁面,頁面中存在通過第三方JavaScript代碼插入的動(dòng)態(tài)廣告(正常的產(chǎn)品需求),上線后發(fā)現(xiàn)第三方的廣告資源存在重復(fù)請求的問題。由于控制廣告插...
摘要:盡可能地將數(shù)據(jù)寫入,例如創(chuàng)建設(shè)置的都會(huì)將數(shù)據(jù)立即的寫入再來看看文檔怎么描述的看看這可愛的默認(rèn)值我們終于知道了當(dāng)我們不做任何設(shè)置時(shí),默認(rèn)采用的是方式顯而易見,使用方式能最大限度的減少與的交互,而在大多數(shù)場景下都是沒有問題的。 0.問題背景 此次問題源于一次挺嚴(yán)重的生產(chǎn)事故:客戶的訂單被重復(fù)生成了,而出問題的代碼其實(shí)很簡單: // .... redisLockUtil.lock(membe...
摘要:為了一探究竟,于是開啟了這次應(yīng)用性能調(diào)優(yōu)之旅。使用即時(shí)編譯器和都能輕輕松松的讓你的應(yīng)用程序在不用做任何修改的情況下,直接提高或者更高的性能。 這是一份事后的總結(jié)。在經(jīng)歷了調(diào)優(yōu)過程踩的很多坑之后,我們最終完善并實(shí)施了初步的性能測試方案,通過真實(shí)的測試數(shù)據(jù)歸納出了 Laravel 開發(fā)過程中的一些實(shí)踐技巧。 0x00 源起 最近有同事反饋 Laravel 寫的應(yīng)用程序響應(yīng)有點(diǎn)慢、20幾個(gè)并...
閱讀 1005·2021-11-15 18:06
閱讀 2371·2021-10-08 10:04
閱讀 2656·2019-08-28 18:03
閱讀 906·2019-08-26 13:42
閱讀 1924·2019-08-26 11:31
閱讀 2431·2019-08-23 17:13
閱讀 932·2019-08-23 16:45
閱讀 2059·2019-08-23 14:11