Rumah > hujung hadapan web > tutorial js > Analisis pemuatan dan pelaksanaan skrip JavaScript dalam persekitaran penyemak imbas: tangguh dan ciri async_kemahiran javascript

Analisis pemuatan dan pelaksanaan skrip JavaScript dalam persekitaran penyemak imbas: tangguh dan ciri async_kemahiran javascript

WBOY
Lepaskan: 2016-05-16 15:20:02
asal
1635 orang telah melayarinya

Ciri tangguh dan tak segerak dipercayai merupakan dua ciri yang kebanyakan pembangun JavaScript "biasa tetapi tidak biasa dengannya". dan kesan "skrip tak segerak". Walau bagaimanapun, mengambil penangguhan sebagai contoh, pembangun mungkin tidak semestinya mengetahui beberapa butiran, seperti: bilakah skrip dengan ciri penangguhan akan ditangguhkan untuk dilaksanakan sama ada skrip dalaman dan skrip luaran boleh menyokong penangguhan; selain pelaksanaan tertangguh, apakah ciri khasnya, dsb. Artikel ini menggabungkan beberapa artikel sedia ada dan perihalan dua ciri dalam dokumen MDN untuk menjalankan kajian dan ringkasan penangguhan dan async yang lebih komprehensif, dengan harapan dapat membantu pembangun menguasai kedua-dua ciri ini dengan lebih baik.

1 Pengenalan

Dalam "Analisis Pemuatan dan Pelaksanaan Skrip JavaScript dalam Persekitaran Pelayar: Urutan Pelaksanaan Kod" kami menyebut bahawa pelaksanaan kod JavaScript akan menyekat penghuraian dan pemaparan halaman serta memuat turun sumber lain . Sudah tentu, kerana JavaScript adalah bahasa berutas tunggal, yang bermaksud bahawa dalam keadaan biasa, kod JavaScript dalam halaman hanya boleh dilaksanakan mengikut urutan dari atas ke bawah Sudah tentu, seperti dalam " Analisis JavaScript Pemuatan dan Pelaksanaan Skrip dalam Persekitaran Penyemak Imbas Seperti yang kami analisis dalam "Jujukan Pelaksanaan ", dalam beberapa kes, seperti apabila memasukkan skrip melalui document.write atau memperkenalkan skrip melalui teknologi skrip dinamik, susunan pelaksanaan kod JavaScript tidak tidak semestinya mengikut perintah yang ketat dari atas ke bawah dan async juga yang kita panggil "situasi tidak normal".

Kami sering mengatakan bahawa pelaksanaan JavaScript adalah menyekat Dalam pembangunan sebenar, penyekatan yang biasanya paling kami bimbangkan dan penyekatan yang paling mempengaruhi pengalaman pengguna haruslah aspek berikut:

[1] Menyekat penghuraian dan pemaparan halaman

[2] Skrip permulaan halaman yang kami tulis (biasanya skrip terikat untuk mendengar acara DOMContentLoaded ini ialah skrip yang kami mahu laksanakan dahulu, kerana kami akan menulis kod yang paling berkaitan dengan interaksi pengguna). di sini.)

[3] Menyekat muat turun sumber luaran pada halaman (seperti gambar)

Jika kami mempunyai operasi skrip yang memakan masa, dan skrip ini menyekat tiga tempat yang kami nyatakan di atas, maka prestasi atau pengalaman pengguna halaman web ini akan menjadi sangat lemah.

Niat asal kedua-dua ciri penangguhan dan async juga adalah untuk menyelesaikan atau mengurangkan kesan penyekatan pada pengalaman halaman Mari kita menganalisis kedua-dua ciri ini terutamanya dari aspek berikut >

[1]Bilakah masa pelaksanaan skrip tertangguh atau tak segerak? Bagaimana pula dengan penyekatan halaman?


[2] Adakah kedua-dua skrip dalaman dan luaran mampu melambatkan atau pelaksanaan tak segerak?


[3] Sejauh manakah pelayar menyokong kedua-dua ciri ini? Adakah terdapat sebarang pepijat yang berkaitan?


[4] Adakah terdapat perkara lain yang perlu diberi perhatian apabila menggunakan skrip yang menggunakan kedua-dua ciri ini?


2 ciri tangguh

2.1 Mengenai masa pelaksanaan skrip penangguhan

Ciri tangguh ialah ciri lanjutan yang ditakrifkan dalam spesifikasi HTML4 Pada mulanya, ia hanya disokong oleh IE4 dan Firefox3.5 Kemudian, pelayar seperti Chrome turut menambah sokongan untuknya, menggunakan defer="defer". defer bermaksud kelewatan, yang bermaksud ia akan menangguhkan pelaksanaan skrip. Dalam keadaan biasa, skrip yang kami perkenalkan akan dimuat turun dan dilaksanakan dengan serta-merta Namun, dengan ciri tangguh, skrip tidak akan dilaksanakan serta-merta selepas dimuat turun, tetapi akan dilaksanakan selepas halaman dihuraikan. Mari kita lihat penjelasan standard HTML4 tentang penangguhan:


tunda: Apabila ditetapkan, atribut boolean ini memberikan petunjuk kepada ejen pengguna bahawa skrip tidak akan menjana sebarang kandungan dokumen (cth., tiada "document.write" dalam javascript) dan dengan itu, ejen pengguna boleh meneruskan penghuraian dan rendering.


Dalam erti kata lain, jika penangguhan ditetapkan, ia memberitahu ejen pengguna bahawa skrip ini tidak akan menghasilkan sebarang kandungan dokumen, supaya ejen pengguna boleh terus menghuraikan dan membuat persembahan. Mari kita lihat sekali lagi perihalan utama penangguhan dalam MDN:


tunda: Jika atribut async tidak ada tetapi atribut tangguh ada, maka skrip dilaksanakan apabila halaman telah selesai menghuraikan


Melalui takrifan dalam standard, kami boleh menjelaskan dengan jelas bahawa skrip tangguh tidak akan menyekat penghuraian halaman, tetapi akan menunggu sehingga penghuraian halaman selesai sebelum melaksanakannya, bagaimanapun, penangguhan yang memakan masa mungkin masih menyekat muat turun sumber luaran, kemudian Adakah ia akan menyekat acara DOMContentLoaded? Malah, skrip tangguh masih dilaksanakan sebelum acara DOMContentLoaded, jadi ia masih akan menyekat skrip dalam DOMContentLoaded. Kita boleh menggunakan angka berikut untuk membantu memahami masa pelaksanaan skrip tangguh:



Menurut definisi dalam standard, skrip dalaman tidak menyokong penangguhan, tetapi pelayar IE9 dan ke bawah menyediakan sokongan penangguhan untuk skrip dalaman.


2.2 menangguhkan sokongan penyemak imbas

Mari kita lihat sokongan penyemak imbas untuk ciri tangguh:


Terdapat pepijat dalam pelayar IE9 dan di bawah, yang akan diterangkan secara terperinci dalam DEMO nanti.

2.3 DEMO: Pengesahan fungsi ciri tangguh

Kami meniru kaedah yang digunakan oleh Olivier Rochard dalam "atribut penangguhan skrip" untuk mengesahkan fungsi atribut penangguhan:

Mula-mula kami menyediakan 6 skrip luaran:

1.js:

ujian = "Saya ketua skrip luaran n";

2.js


ujian = "Saya adalah skrip luaran badan";


3.js


ujian = "Saya adalah skrip luar bawah n";

tangguh1.js

ujian = "Saya mengetuai skrip kelewatan luaran n";

tunda2.js


ujian = "Saya skrip kelewatan luar badan n";


tunda3.js


ujian = "Saya adalah skrip kelewatan luaran bahagian bawah";

Kod dalam HTML ialah:


Dalam kod, untuk memudahkan pelaksanaan acara DOMContentLoaded, kami memperkenalkan jQuery (artikel kemudian akan memperkenalkan cara untuk melaksanakan sendiri DOMContentLoaded yang serasi Kemudian, kami memperkenalkan skrip kelewatan di kepala, di dalam badan dan di luar badan skrip dan skrip biasa, dan merekodkan status pelaksanaan setiap kod melalui rentetan global Mari kita lihat hasil pelaksanaan dalam setiap penyemak imbas:

IE7 IE9 IE10 CHROME firefox
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>defer attribute test</title>
<script src="http://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script>
<script type="text/javascript">var test = "";</script>
<script src="defer1.js" type="text/javascript" defer="defer"></script>
<script src="1.js" type="text/javascript"></script>
<script defer="defer">
test += "我是head延迟内部脚本\n";
</script>
<script>
test += "我是head内部脚本\n";
</script>
</head>
<body>
<button id="test">点击一下</button>
<script src="defer2.js" type="text/javascript" defer="defer"></script>
<script src="2.js" type="text/javascript"></script>
</body>
<script src="defer3.js" type="text/javascript" defer="defer"></script>
<script src="3.js" type="text/javascript"></script>
<script>
$(function(){
test += "我是DOMContentLoaded里面的脚本
";
})
window.onload = function(){
test += "我是window.onload里面的脚本
";
var button = document.getElementById("test");
button.onclick = function(){
alert(test);
}
}
</script>
</html> 
Salin selepas log masuk
Saya adalah ketua skrip luaran Saya ialah skrip dalaman kepala

Saya ialah skrip luaran badan
Saya adalah skrip luaran bahagian bawah

Saya mengetuai skrip kelewatan luaran

Saya sedang menunda skrip dalaman

IE7 IE9 IE10 CHROME firefox

我是head外部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是head延迟内部脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是head延迟内部脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head延迟内部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

我是head外部脚本
我是head延迟内部脚本
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本

<br />我是head外部脚本
<span style="color: rgb(255,0,0)">我是head延迟内部脚本</span>
我是head内部脚本
我是body外部脚本
我是底部外部脚本
我是head外部延迟脚本
我是body外部延迟脚本
我是底部外部延迟脚本
<span style="color: rgb(255,0,0)">我是DOMContentLoaded里面的脚本
我是window.onload里面的脚本</span>
Salin selepas log masuk
Saya ialah skrip kelewatan luaran badan <🎜> Saya adalah skrip kelewatan luaran bahagian bawah <🎜> Saya ialah skrip dalam DOMContentLoaded<🎜> Saya ialah skrip dalam window.onload<🎜>
<🎜>Saya adalah ketua skrip luaran<🎜> Saya ialah skrip dalaman kepala<🎜> Saya ialah skrip luaran badan<🎜> Saya adalah skrip luaran bahagian bawah <🎜> Saya mengetuai skrip kelewatan luaran <🎜> Saya sedang menunda skrip dalaman<🎜> Saya ialah skrip kelewatan luaran badan <🎜> Saya adalah skrip kelewatan luaran bahagian bawah <🎜> Saya ialah skrip dalam DOMContentLoaded<🎜> Saya ialah skrip dalam window.onload<🎜> <🎜>Saya adalah ketua skrip luaran<🎜> Skrip dalaman saya tertunda<🎜> Saya ialah skrip dalaman kepala<🎜> Saya ialah skrip luaran badan<🎜> Saya adalah skrip luaran bahagian bawah <🎜> Saya mengetuai skrip kelewatan luaran <🎜> Saya ialah skrip kelewatan luaran badan <🎜> Saya adalah skrip kelewatan luaran bahagian bawah <🎜> Saya ialah skrip dalam DOMContentLoaded<🎜> Saya ialah skrip dalam window.onload<🎜> <🎜>Saya adalah ketua skrip luaran<🎜> Skrip dalaman saya tertunda<🎜> Saya ialah skrip dalaman kepala<🎜> Saya ialah skrip luaran badan<🎜> Saya adalah skrip luaran bahagian bawah <🎜> Saya mengetuai skrip kelewatan luaran <🎜> Saya ialah skrip kelewatan luaran badan <🎜> Saya adalah skrip kelewatan luaran bahagian bawah <🎜> Saya ialah skrip dalam DOMContentLoaded<🎜> Saya ialah skrip dalam window.onload<🎜> <🎜>

从输出的结果中我们可以确定,只有IE9及以下浏览器支持内部延迟脚本,并且defer后的脚本都会在DOMContentLoaded事件之前触发,因此也是会堵塞DOMContentLoaded事件的。

2.4 DEMO:IE<=9的defer特性bug

从2.3节中的demo可以看出,defer后的脚本还是能够保持执行顺序的,也就是按照添加的顺序依次执行。而在IE<=9中,这个问题存在一个bug:假如我们向文档中增加了多个defer的脚本,而且之前的脚本中有appendChild,innerHTML,insertBefore,replaceChild等修改了DOM的接口调用,那么后面的脚本可能会先于该脚本执行。可以参考github的issue:https://github.com/h5bp/lazyweb-requests/issues/42

我们通过DEMO验证一下,首先修改1.js的代码为(这段代码只为模拟,事实上这段代码存在极大的性能问题):

document.body.innerHTML = "

我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
document.body.innerHTML += "
我是后来加入的
";
alert("我是第1个脚本");

2.js

alert("我是第2个脚本");

修改HMTL中的代码为:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>defer bug in IE=9 test</title>
<script src="1.js" type="text/javascript" defer="defer"></script>
<script src="2.js" type="text/javascript" defer="defer"></script>
</head>
<body>
</body>
</html>
Salin selepas log masuk

正常情况下,浏览器中弹出框的顺序肯定是:我是第1个脚本-》我是第2个脚本,然而在IE<=9中,执行结果却为:我是第2个脚本-》我是第1个脚本,验证了这个bug。

2.5 defer总结

在总结之前,首先要说一个注意点:正如标准中提到的,defer的脚本中不应该出现document.write的操作,浏览器会直接忽略这些操作。

总的来看,defer的作用一定程度上与将脚本放置在页面底部有一定的相似,但由于IE<=9中的bug,如果页面中出现多个defer时,脚本的执行顺序可能会被打乱从而导致代码依赖可能会出错,因此实际项目中很少会使用defer特性,而将脚本代码放置在页面底部可以替代defer所提供的功能。

3 async特性

3.1 关于async脚本的执行时机

async特性是HTML5中引入的特性,使用方式为:async="async",我们首先看一下标准中对于async特性的相关描述:

async:If the async attribute is present, then the script will be executed asynchronously, as soon as it is available.

需要指出,这里的异步,指的其实是异步加载而不是异步执行,也就是说,浏览器遇到一个async的script标签时,会异步的去加载(个人认为这个过程主要是下载的过程),一旦加载完毕就会执行代码,而执行的过程肯定还是同步的,也就是阻塞的。我们可以通过下图来综合理解defer和async:


这样来看的话,async脚本的执行时机是无法确定的,因为脚本何时加载完毕也是不确定的。我们通过下面的demo来感受一下:

async1.js

alert("我是异步的脚本");

HTML代码:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>async attribute test</title>
<script src="/delayfile.php&#63;url=http://localhost/js/load/async1.js&delay=2" async="async" type="text/javascript"></script>
<script>
alert("我是同步的脚本");
</script>
</head>
<body>
</body>
</html> 
Salin selepas log masuk

Ici, nous empruntons le script delayfile dans « Analyse du chargement et de l'exécution du script JavaScript dans un environnement de navigateur : séquence d'exécution de code » pour fournir un délai dans les navigateurs prenant en charge l'asynchrone, l'ordre des boîtes contextuelles de ce script est généralement le même. : Je suis un script synchrone -> Je suis un script asynchrone.

3.2 Prise en charge du navigateur pour l'asynchrone

Jetons un coup d'œil à la prise en charge des fonctionnalités asynchrones par le navigateur :

Comme vous pouvez le voir, seul IE10 prend en charge la fonctionnalité asynchrone, Opera Mini ne prend pas en charge la fonctionnalité asynchrone et async ne prend pas en charge les scripts internes.

Résumé asynchrone 3.3

async fait référence aux scripts asynchrones, c'est-à-dire que les scripts sont chargés de manière asynchrone, le processus de chargement ne provoquera pas de blocage, mais le moment d'exécution des scripts asynchrones est incertain, et l'ordre d'exécution est également incertain, donc les scripts utilisant async devraient l'être. Scripts qui ne s'appuient sur aucun code (comme un code de statistiques tiers ou un code publicitaire), sinon cela provoquera des erreurs d'exécution.

4 Problèmes de priorité entre le report et l'asynchrone

C'est plus facile à comprendre. La norme stipule :

[1] Si l'élément

Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan