国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

埋點統計優化,首屏加載速度提升

開發 前端
統計代碼會影響業務首屏加載嗎?同步引入方式,當然會,我的業務代碼還沒加載,首屏就加載一大段統計的jsdk,在移動端頁面打開要求比較高的苛刻條件下,首屏優化,你可以在埋點統計上做些優化,那么頁面加載會有一個很大的提升,本文是一篇筆者關于埋點優化的筆記,希望看完在項目中有所思考和幫助。

埋點統計在我們業務里經常有遇到,或者很普遍的,我們自己網站也會加入第三方統計,我們會看到動態加載方式去加載jsdk,也就是你常常看到的insertBefore操作,我們很少考慮到為什么這么做,直接同步加載不行嗎?

統計代碼會影響業務首屏加載嗎?同步引入方式,當然會,我的業務代碼還沒加載,首屏就加載一大段統計的jsdk,在移動端頁面打開要求比較高的苛刻條件下,首屏優化,你可以在埋點統計上做些優化,那么頁面加載會有一個很大的提升,本文是一篇筆者關于埋點優化的筆記,希望看完在項目中有所思考和幫助。

最近遇到一個問題,先看一段代碼。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>埋點</title>
<script>
window.formateJson = (data) => JSON.stringify(data, null, 2);
</script>
<script async defer>
(function (win, head, attr, script) {
console.log("---111---");
win[attr] = win[attr] || [];
const scriptDom = document.createElement(script);
scriptDom.async = true;
scriptDom.defer = true;
scriptDom.src = "./js/tj.js";
scriptDom.onload = function () {
win[attr].push({
id: "maic",
});
win[attr].push({
id: "Tom",
});
console.log("---2222---");
console.log(formateJson(win[attr]));
};
setTimeout(() => {
console.log("setTimeout---444---");
head.parentNode.insertBefore(scriptDom, head);
}, 1000);
})(window, document.getElementsByTagName("head")[0], "actd", "script");
</script>
<script async defer src="./js/app.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>

我們會發現,打印的順序結果是下面這樣的:

---111---
app.js:2 ---333--- start load app.js
app.js:4 [
{
"id": "pink"
}
]
(index):30 setTimeout---444---
(index):26 ---2222---
(index):27 [
{
"id": "pink"
},
{
"id": "maic"
},
{
"id": "Tom"
}
]

冥思苦想,我們發現最后actd的結果是:

[
{
"id": "pink"
},
{
"id": "maic"
},
{
"id": "Tom"
}
]

其實我本意想要的結果是先添加maic,Tom,最后添加pink,需求就是,必須先在這個ts.js執行后,預先添加基礎數據,然后在其他業務app.js添加其他數據,所以此時,無論如何都滿足不了我的需求。

試下想,為什么沒有按照我預期的要求走,問題就是出現在這個onload方法上。

onload事件

于是查詢資料尋得,onload事件是會等引入的外部資源加載完畢后才會觸發。

外部資源加載完畢是什么意思?

舉個栗子,我在引入的index2.html引入index2.js,然后在引入腳本上寫一個onload事件測試loadIndex2方法是否在我延時加載后進行調用的。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
function loadIndex2() {
console.log("script loader...");
}
</script>
<script src="./js/index2.js" onload="loadIndex2()"></script>
</body>
</html>

index2.js中寫入一段代碼:

var startTime = Date.now()
const count = 1000;
let wait = 10000;
/// 設置延時
const time = wait * count;
for (let i = 0; i < time; i++) { }

var endTime = Date.now()
console.log(startTime, endTime)
console.log(`延遲了:${Math.ceil((endTime - startTime) / 1000)}s后執行的`)

最后看下打印結果。

圖片

所以可以證實,onload是會等資源下載完了后,才會立即觸發。

所以我們回頭來看。

在瀏覽器的事件循環中,同步任務主線程肯定優先會先順序執行。

從打開印---111---,

然后到onload此時不會立即執行。

遇到定時器,定時器設置了1s后會執行,是個宏任務,會放入隊列中,此時不會立即執行。

然后接著會執行 <script async defer src="./js/app.js"></script>腳本。

所以此時,執行該腳本后,我們可以看到會先執行push方法。

所以我們看到pink就最先被推入數組中,當該腳本執行完畢后,此時會去執行定時器。

定時器里我們看到我們插入方式insertBefore,當插入時成功時,此時會調用onload方法,所以此時就會添加maic與Tom。

很明顯,我們此時的需求不滿足我們的要求,而且一個onload方法已經成了攔路虎。

那么我去掉onload試試,因為onload方法只會在腳本加載完畢后去執行,他只會等執行定時器后,成功插入腳本后才會真正執行,而此時其他腳本已經優先它的執行了。

那該怎么解決這個問題呢?

我把onload去掉試試,于是我改成了下面這樣:

<script async defer>
(function (win, head, attr, script) {
console.log("---111---");
win[attr] = win[attr] || [];
const scriptDom = document.createElement(script);
scriptDom.async = true;
scriptDom.defer = true;
scriptDom.src = "./js/tj.js";
win[attr].push({
id: "maic",
});
win[attr].push({
id: "Tom",
});
console.log("---2222---");
console.log(formateJson(win[attr]));
setTimeout(() => {
console.log("setTimeout---444---");
head.parentNode.insertBefore(scriptDom, head);
}, 1000);
})
(window, document.getElementsByTagName("head")
[0], "actd", "script");
</script>

去掉onload后,我確實達到了我想要的結果。

最后的結果是:

[
{
"id": "maic"
},
{
"id": "Tom"
},
{
"id": "pink"
}
]

但是你會發現:

圖片

我先保證了window.actd添加了我預定提前添加的基礎信息,但此時,這個腳本并沒有真正添加到dom中,我們執行完同步任務后,就會執行app.js,當1s后,我才真正執行了這個插入的腳本,而且我統計腳本你會發現此時是先執行了app.js再加載tj.js的。

當執行setTimeout時,我們會發現先執行了內部腳本,然后才執行打印。

<script async defer>
(function (win, head, attr, script) {
console.log("---111---");
win[attr] = win[attr] || [];
const scriptDom = document.createElement(script);
scriptDom.async = true;
scriptDom.defer = true;
scriptDom.src = "./js/tj.js";
win[attr].push({
id: "maic",
});
win[attr].push({
id: "Tom",
});
console.log("---2222---");
console.log(formateJson(win[attr]));
setTimeout(() => {
console.log("setTimeout---444444---");
window.actd.push({
id: "setTimeout",
});
head.parentNode.insertBefore(scriptDom, head);
console.log(formateJson(window.actd));
}, 1000);
})(window, document.getElementsByTagName("head")[0], "actd", "script");
</script>

最后的結果,可以看到是這樣的:

[
{
"id": "maic"
},
{
"id": "Tom"
},
{
"id": "pink"
},
{
"id": "setTimeout"
}
]

看到這里不知道你心里有沒有一個疑問,為什么在動態插入腳本時,我要用一個定時器1s鐘?為什么我需要用insertBefore這種方式插入腳本?,我同步方式引入不行嗎?不要定時器又會有什么樣的結果?

我們通常在接入第三方統計時,貌似都是一個這樣一個insertBefore插入的jsdk方式(但是一般我們都是同步方式引入jsdk)。

沒有使用定時器(3237ms)

<script async defer>
(function (win, head, attr, script) {
...
console.log("setTimeout---444444---");
window.actd.push({
id: "setTimeout",
});
head.parentNode.insertBefore(scriptDom, head);
console.log(formateJson(window.actd));
})(window, document.getElementsByTagName("head")[0], "actd", "script");
</script>

圖片

結果:

[
{
"id": "maic"
},
{
"id": "Tom"
},
{
"id": "setTimeout"
},
{
"id": "pink"
},
]

使用用定時器的(1622ms)

<script async defer>
(function (win, head, attr, script) {
...
setTimeout(() => {
console.log("setTimeout---444444---");
window.actd.push({
id: "setTimeout",
});
head.parentNode.insertBefore(scriptDom, head);
console.log(formateJson(window.actd));
}, 1000);
})(window, document.getElementsByTagName("head")[0], "actd", "script");
</script>

圖片

當我們用瀏覽器的Performance去比較兩組數據時,我們會發現總長時間,使用定時器的性能大概比沒有使用定時器的性能時間上大概要少50%,在summary中所有數據均有顯示的提升。

不經感嘆,就一個定時器這一點點的改動,對整個應用提升有這么大的提升,我領導說,快應用在線加載時,之前因為這個統計js的加載明顯阻塞了業務頁面打開速度,做了這個優化后,打開應用顯著提升不少。

我們再繼續上一個問題,為什么不同步加載?

我把代碼改造一下,去除了一些無關緊要的代碼:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>js執行的順序問題</title>
<script>
window.formateJson = (data) => JSON.stringify(data, null, 2);
</script>
<script async defer src="./js/tj.js"></script>
<script async defer>
(function (win, head, attr, script) {
win[attr] = win[attr] || [];
win[attr].push({
id: "maic",
});
win[attr].push({
id: "Tom",
});
console.log("---2222---");
console.log(formateJson(win[attr]));
})(window, document.getElementsByTagName("head")[0], "actd", "script");
</script>
<script async defer src="./js/app.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>

結果

[
{
"id": "maic"
},
{
"id": "Tom"
},
{
"id": "pink"
}
]

嘿,需求是達到了,因為我的業務app.js加的數據是最后一條,說明業務功能上是ok的,但是我們看下分析數據。

首先肯定是加載順序會發生變化,會先加載tj.js然后再加載業務app.js,你會發現同步加載這種方式有個弊端,假設tj.js很大,那么是會阻塞影響頁面首屏打開速度的,所以在之前采用異步,定時器方式,首屏加載會有顯著提升。

同步加載(1846ms)

圖片

圖片

我們發現tj.js與app.js相隔的時間很少,且我們從火焰圖中分析看到,Summary的數據是1846ms。

綜上比較,雖然同步加載依然比不上使用定時器的加載方式,使用定時器相比較同步加載,依然是領先11%左右。

異步標識async/defer

在上面的代碼中,我們多次看到async和defer標識,在之前文章中筆者有寫過一篇你真的了解esModule嗎,闡述一些關于script標簽中type="moudle", defer,async的幾個標識,今天再次回顧下。

其實從腳本優先級來看,同步的永遠優先最高,當一個script標簽沒有指定任何標識時,此時根據js引擎執行來說,誰放前面,誰就會優先執行,前面沒執行完,后面同步的script就不會執行。

注意到沒有,我在腳本上有加async與defer。

在上面栗子中,我們使用insertBefore方式,這就將該插入的js腳本的優先級降低了。

我們從上面火焰圖中可以分析得處結論,排名先后順序依次如下:

1、setTimeout+insertBefore

執行順序:app.js->tj.js

2、同步腳本加載

執行順序:tj.js->app.js

3、不使用定時器+insertBefore

執行順序:app.js->tj.js

當我們知道在1中,app.js優先于tj.js

因為insertBefore就是一種異步動態加載方式

舉個例子:

<script async defer>
// 執行
console.log(1)
// 2 insertBefore 這里再動態添加js
</script>
<script async defer>
// 執行
console.log(3)
</script>

執行關系就是1,3,2。

關于async與defer誰先執行時,defer的優先級比較低,會等異步標識的async下載完后立馬執行,然后再執行defer的腳本,具體可以參考以前寫的一篇文章你真的了解esModule嗎。

總結

  • 統計腳本,我們可以使用定時器+insertBefore方式可以大大提高首屏的加載速度,這也給我們了一些啟發,首屏加載,非業務代碼,比如埋點統計可以使用該方案做一點小優化加快首屏加載速度。
  • 如果使用insertBefore方式,非常不建議同步方式insertBefore,這種方式還不如同步加載統計腳本。
  • 在特殊場景下,我們需要加載統計腳本,有基礎信息的依賴后,我們也需要在業務代碼使用統計,我們不要在動態加載腳本的同時使用onload,在onload中嘗試添加基礎信息,實際上這種方式并不能滿足你的需求。
  • 一些關于async與defer的特性,記住,執行順序,同步任務會優先執行,async是異步,腳本下載完就執行,defer優先級比較低。
  • 本文示例code example[1]

[1]code example: https://github.com/maicFir/lessonNote/tree/master/javascript/21-js異步執行

責任編輯:武曉燕 來源: Web技術學苑
相關推薦

2023-12-17 14:49:20

前端首屏時間

2025-03-10 00:00:50

2021-07-01 12:10:31

性能優化React

2022-05-14 08:35:12

Webpack前端

2009-09-04 11:34:31

NetBeans優化

2023-11-25 20:16:22

前端

2021-01-08 09:40:40

優化VUE性能

2013-05-22 09:20:42

Chrome 27瀏覽器

2012-06-08 09:41:18

Web

2024-11-01 07:30:00

2017-12-05 13:41:02

SQL數據庫SQL查詢

2024-04-17 08:23:50

WebView技巧優化

2017-08-16 10:57:25

H5HTML開發

2017-12-28 14:54:04

Android代碼埋點全埋點

2016-09-30 13:11:31

前端后端網頁速度

2010-12-24 08:57:44

Google加速工具page-speed

2024-11-28 10:04:14

2024-02-23 08:18:32

首屏產品瀏覽器

2015-10-29 09:40:54

優化頁面加載速度

2023-12-13 18:46:50

FlutterAOP業務層
點贊
收藏

51CTO技術棧公眾號

国产精品一区二区欧美| 一区二区日本视频| 91亚洲精品在线观看| 日韩成人午夜电影| 黄大色黄女片18第一次| 欧美日韩国产首页| 亚洲日本在线观看视频| 91av视频在线免费观看| 亚洲在线免费| 2025韩国理伦片在线观看| 欧美乱熟臀69xxxxxx| 在线观看欧美| 蜜桃欧美视频| 国产精品三级在线观看| 青青草原av在线| 国产精品久久久久久超碰| 国产99精品国产| 亚洲乱亚洲乱妇| 国产精品久久97| 99国产精品国产精品久久| 日本美女在线中文版| 97高清免费视频| 国产乱淫av一区二区三区| 国产精品免费观看| 日本中文字幕久久看| 丁香婷婷深情五月亚洲| аⅴ资源新版在线天堂| 91av网站在线播放| 成人国产亚洲欧美成人综合网 | 亚洲成人激情综合网| 福利精品一区| 国产综合欧美在线看| 亚洲乱码国产乱码精品精的特点| 偷拍自拍在线看| 成人免费视频网站入口| 亚洲精品一卡二卡| 97品白浆高清久久久久久| 韩国无码av片在线观看网站| 欧美一级艳片视频免费观看| 女生裸体视频一区二区三区| xxx亚洲日本| 俺去了亚洲欧美日韩| 美女视频一区二区三区| 亚洲第一se情网站| 成人写真视频福利网| 久久色.com| 少女频道在线观看免费播放电视剧| 欧美成人sm免费视频| 日韩免费视频一区| 日韩精品网站| 啊啊啊好爽视频| 欧美激情精品久久久久久久变态| 成人免费毛片嘿嘿连载视频| 在线成人av观看| 黄频视频在线观看| 日韩一区二区高清| 日韩一区二区免费看| 一区二区三区高清在线视频| 国产精品久久久久久久久久久不卡| 中文字幕亚洲成人| 欧美日韩一本| 韩国97影院| 国产精品一久久香蕉国产线看观看| 亚洲欧洲一区二区三区| 日韩电影不卡一区| baoyu777.永久免费视频| 38少妇精品导航| 一区二区不卡在线播放 | 久久精品国产秦先生| 26uuu亚洲电影在线观看| 久久久综合香蕉尹人综合网| 欧美日韩国产大片| 亚洲日本视频| av免费看在线| 亚洲精品免费在线看| 欧美精品一区二| 国产精品69毛片高清亚洲| 亚洲播播91| 日韩网址在线观看| 久久理论片午夜琪琪电影网| 成人欧美一区二区三区1314| 亚洲系列另类av| 一区二区三区区四区播放视频在线观看 | 91精品欧美久久久久久动漫| 性色一区二区三区| а√天堂8资源在线| 无码粉嫩虎白一线天在线观看| 久久99青青精品免费观看| 国产欧美一区在线| 激情五月综合网| 欧美性猛交xxx乱大交3蜜桃| 亚洲综合第一| 久久综合色88| 亚洲亚洲精品在线观看| 亚洲高清成人| 樱桃视频成人在线观看| 另类小说色综合| 91在线观看欧美日韩| 日本精品视频一区二区三区| 久久久久国产一区二区| 深夜成人福利| 成人综合av| 国产在线精品一区二区三区》| 日韩av在线直播| 国产三级精品在线| 7777久久香蕉成人影院| 99在线视频影院| 久久精品午夜福利| 成人在线一区二区| 精品亚洲夜色av98在线观看| 国产精品成人一区二区三区夜夜夜| 国产精品久久占久久| 人人超在线公开视频| 99精品视频在线看| 91在线播放视频| 亚洲免费视频在线观看| 成人免费在线观看入口| 亚洲一区成人| 高清日韩欧美| 中文字幕中文字幕在线十八区| 动漫av免费观看| 精品欧美一区二区三区久久久| 俺去亚洲欧洲欧美日韩| 色香蕉久久蜜桃| 成人黄色在线看| 精品成人国产| 亚洲精品午夜| 国产一线二线在线观看| 欧美成人福利在线观看| 鲁丝片一区二区三区| 久久久精品免费| 欧美狂野另类xxxxoooo| 中文子幕无线码一区tr| 日韩精品一卡二卡三卡四卡无卡| 成人精品毛片| 韩国成人免费视频| 伊人发布在线| 人妻熟妇乱又伦精品视频| 国产在线一区二区三区四区| 高清欧美性猛交xxxx黑人猛交| 精品精品欲导航| 亚洲aaa精品| 久久综合狠狠综合| 日日夜夜精品免费视频| 日本一二区不卡| 午夜日韩影院| 在线视频超级| www在线免费观看| 91大神影片| av免费观看国产| 日韩亚洲视频| 亚洲影视九九影院在线观看| 久久久久久国产精品美女| 日韩成人性视频| 欧美日韩国产免费一区二区| 亚洲色图19p| 2021中文字幕一区亚洲| 麻豆精品视频在线| 亚洲国产清纯| 久久社区一区| 天天躁日日躁狠狠躁欧美巨大小说 | 欧美一区三区二区在线观看| 国产精品网红福利| 久久精品99久久香蕉国产色戒| 日韩一级黄色大片| 午夜成人免费电影| 中文字幕二三区不卡| 国产成人一区在线| 香蕉久久夜色精品| 亚洲情侣在线| 免费视频一区三区| 精品一区二区三区在线观看视频 | 一本一本大道香蕉久在线精品 | 羞羞答答成人影院www| 99国产精品免费网站| 88xx成人免费观看视频库| 美女国产在线| 黄色在线小视频| 免费观看又污又黄在线观看国产| 成年人深夜视频| 欧美亚州在线观看| 国产免费高清一区| 亚洲一区二区免费在线| 国产精品美女视频网站| 美女精品久久久| 色偷偷噜噜噜亚洲男人的天堂| 亚洲高清av在线| 精品久久久久99| 欧美xxxx老人做受| 欧美va在线播放| 日韩精品在线一区| 日韩午夜激情视频| 日韩欧美高清在线| 欧美成人精品3d动漫h| 日韩视频永久免费| 精品久久久久久无| 日韩av最新在线观看| 亚洲欧美中文在线视频| 亚洲美女免费精品视频在线观看| 亚洲国语精品自产拍在线观看|