komut dosyalarını yükleme ve yürütme


265

Bir html sayfasına JavaScript eklemenin birçok farklı yolu vardır. Aşağıdaki seçenekleri biliyorum:

  • satır içi kod veya harici URI'den yüklenmiş
  • <head> veya <body> etiketine dahil [ 1 , 2 ]
  • hiç yok, deferveyaasync niteliği olmayan (yalnızca harici komut dosyaları)
  • statik kaynağa dahil edilir veya diğer komut dosyaları tarafından dinamik olarak eklenir (farklı ayrıştırma durumlarında, farklı yöntemlerle)

Harddisk, javascript: URI ve onEvent-attributes [ 3 ] ' dan tarayıcıları saymıyorum, JS'nin çalıştırılması için zaten 16 alternatif var ve eminim bir şey unuttum.

Hızlı (paralel) yükleme ile o kadar ilgilenmiyorum, yürütme siparişini daha fazla merak ediyorum (yükleme sırasına ve belge sırasına bağlı olabilir ). Gerçekten tüm vakaları kapsayan iyi bir (çapraz tarayıcı) referans var mı? Örneğin, http://www.websiteoptimization.com/speed/tweak/defer/ yalnızca 6 tanesiyle ilgilenir ve çoğunlukla eski tarayıcıları test eder.

Korkmadığım için, özel sorum şu: Başlatma ve komut dosyası yüklemesi için bazı (harici) baş komut dosyalarımız var. Sonra vücudun sonunda iki statik, satır içi komut dosyası var. Birincisi, kod yükleyicinin gövdeye dinamik olarak başka bir kod öğesi (harici j'lere referans vererek) eklemesine izin verir. Statik, satır içi komut dosyalarının ikincisi, eklenen dış komut dosyasından js kullanmak istiyor. İdam edilen diğer kişiye güvenebilir mi (ve neden :-)?


Baktığınız Engelleme olmadan Yükleme Script Steve Souders tarafından? Şimdi biraz tarihli, ancak yine de belirli bir komut dosyası yükleme tekniği verildiğinde tarayıcı davranışıyla ilgili bazı değerli bilgiler içeriyor.
Josh Habdas

Yanıtlar:


331

Komut dosyalarını dinamik olarak yüklemiyorsanız veya bunları olarak işaretlemiyorsanız deferveyaasync , o zaman komut sayfasında karşılaşılan sırayla yüklenir. Harici bir komut dosyası mı yoksa satır içi bir komut dosyası mı olduğu önemli değil - sayfada karşılaştıkları sırayla yürütülürler. Harici komut dosyalarından sonra gelen satır içi komut dosyaları, yüklenmeden ve çalıştırılmadan önce gelen tüm dış komut dosyalarına kadar tutulur.

Zaman uyumsuz komut dosyaları (nasıl zaman uyumsuz olarak belirtildiklerinden bağımsız olarak) öngörülemeyen bir sırada yüklenir ve çalıştırılır. Tarayıcı bunları paralel olarak yükler ve istediği sırayla çalıştırmak ücretsizdir.

Birden fazla eşzamansız şey arasında tahmin edilebilir bir düzen yoktur. Tahmin edilebilir bir sipariş gerekiyorsa, uygun olmayan şeyler yüklendiğinde zaman uyumsuz komut dosyalarından yük bildirimleri için kayıt ve el ile sıralı javascript çağrılarını kodlayarak kodlanması gerekir.

Bir komut dosyası etiketi dinamik olarak eklendiğinde, yürütme sırasının nasıl davrandığı tarayıcıya bağlı olacaktır. Bu referans makalede Firefox'un nasıl davrandığını görebilirsiniz . Özetle, Firefox'un daha yeni sürümleri, komut dosyası etiketi başka türlü ayarlanmadığı sürece senkronize olarak dinamik olarak eklenen bir komut dosyası etiketini varsayılan olarak ayarlar.

İle bir komut dosyası etiketi asyncyüklenir yüklenmez çalıştırılabilir. Aslında, tarayıcı ayrıştırıcıyı yaptığı her şeyden duraklatabilir ve o komut dosyasını çalıştırabilir. Yani, neredeyse her zaman çalışabilir. Komut dosyası önbelleğe alındıysa, hemen çalıştırılabilir. Betiğin yüklenmesi biraz zaman alırsa, ayrıştırıcı tamamlandıktan sonra çalıştırılabilir. Hatırlanması gereken tek şey, asyncher zaman çalışabileceği ve o zamanın öngörülebilir olmadığıdır.

İle bir komut dosyası etiketi deferAyrıştırıcının tamamı tamamlanıncaya kadar bekleyen daha sonra işaretlenen tüm komut dosyalarını karşılandıkları defersırayla çalıştırır . Bu, birbirine bağlı olan birkaç komut dosyasını işaretlemenizi sağlar defer. Hepsi belge ayrıştırıcısı bitene kadar ertelenecek, ancak bağımlılıklarını koruyarak karşılaştıkları sırayla yürütüleceklerdir. deferScriptler ayrıştırıcı tamamlandıktan sonra işlenecek bir sıraya düşüyor gibi düşünüyorum . Teknik olarak, tarayıcı her an arka planda komut dosyalarını indirirken olabilir, ancak bunlar yürütmek veya ayrıştırıcı sayfasını ayrıştırma ve ayrıştırma ve işaretlenmemiş tüm satır içi komut dosyalarını çalıştırarak yapılır sonrasına kadar ayrıştırıcı engellemez deferya async.

İşte bu makaleden bir alıntı:

betiğe eklenen komut dosyaları IE ve WebKit'te eşzamansız olarak, Opera ve 4.0 öncesi Firefox'ta eşzamanlı olarak yürütülür.

HTML5 spesifikasyonunun ilgili bölümü (daha yeni uyumlu tarayıcılar için) burada . Orada zaman uyumsuz davranış hakkında çok şey var. Açıkçası, bu özellik, davranışlarını belirlemek için muhtemelen test etmeniz gereken eski tarayıcılar (veya hatalı uyumlu tarayıcılar) için geçerli değildir.

HTML5 spesifikasyonundan bir fiyat teklifi:

Ardından, durumu tanımlayan aşağıdaki seçeneklerden ilkine uyulmalıdır:

Öğenin src özniteliği varsa ve öğenin erteleme özniteliği varsa ve öğe "ayrıştırıcıya eklenen" olarak işaretlenmişse ve öğenin zaman uyumsuz bir özniteliği yoksa Öğe, listenin sonuna eklenmelidir. belge öğeyi oluşturan ayrıştırıcının Dokümanı ile ilişkili ayrıştırma bittiğinde yürütülecek komut dosyaları.

Getirme algoritması tamamlandıktan sonra ağ oluşturma görev kaynağının görev kuyruğuna yerleştirdiği görev, öğenin "ayrıştırıcı tarafından yürütülmeye hazır" bayrağını ayarlamalıdır. Ayrıştırıcı komut dosyasının yürütülmesini yönetir.

Öğenin src özniteliği varsa ve öğe "ayrıştırıcıya eklenen" olarak işaretlenmişse ve öğenin async özniteliği yoksa Öğe, öğeyi oluşturan ayrıştırıcının Dokümanının bekleyen ayrıştırma-engelleme komut dosyasıdır. (Belge başına aynı anda yalnızca bir tane komut dosyası olabilir.)

Getirme algoritması tamamlandıktan sonra ağ oluşturma görev kaynağının görev kuyruğuna yerleştirdiği görev, öğenin "ayrıştırıcı tarafından yürütülmeye hazır" bayrağını ayarlamalıdır. Ayrıştırıcı komut dosyasının yürütülmesini yönetir.

Eleman bir src özelliğini yok ve eleman olarak işaretlendi "Eğer ayrıştırıcı tarafından eklenmiş" ve komut dosyası elemanı oluşturulan HTML ayrıştırıcı veya XML ayrıştırıcı Belge komut engelleyen bir stil sayfası olan elementtir öğeyi oluşturan ayrıştırıcının Belgesinin ayrıştırma-engelleme komut dosyası bekleniyor. (Belge başına aynı anda yalnızca bir tane komut dosyası olabilir.)

Öğenin "ayrıştırıcı tarafından yürütülmeye hazır" bayrağını ayarlayın. Ayrıştırıcı komut dosyasının yürütülmesini yönetir.

Öğenin src özniteliği varsa, eşzamansız özniteliği yoksa ve "zorla eşzamansız" bayrak kümesi yoksa Öğe, mümkün olan en kısa sürede yürütülecek komut dizileri listesinin sonuna eklenmelidir bir komut dosyası algoritması hazırlandığı sırada komut dosyası öğesinin Belgesi ile.

Getirme algoritması tamamlandıktan sonra ağ görevi kaynağının görev kuyruğuna yerleştirdiği görev aşağıdaki adımları çalıştırmalıdır:

Öğe şimdi, yukarıda eklendiği en kısa sürede sırayla yürütülecek komut dosyaları listesindeki ilk öğe değilse , öğeyi hazır olarak işaretleyin, ancak henüz komut dosyasını çalıştırmadan bu adımları iptal edin.

Yürütme: Bu komut dosyası listesindeki ilk komut dosyası öğesine karşılık gelen komut dosyasını, en kısa sürede sırayla yürütür.

En kısa sürede sırayla yürütülecek olan komut dosyaları listesinden ilk öğeyi kaldırın.

Mümkün olan en kısa sürede yürütülecek komut dosyaları listesi hala boş değilse ve ilk giriş zaten hazır olarak işaretlenmişse yürütme etiketli adıma geri dönün.

Öğenin src özniteliği varsa Öğe, bir komut dosyası hazırlama algoritması başlatıldığı sırada, komut dosyası öğesinin Belgesini mümkün olan en kısa sürede yürütecek olan komut dosyası kümesine eklenmelidir.

Getirme algoritması tamamlandıktan sonra ağ görev kaynağının görev kuyruğuna yerleştirdiği görevin komut dosyası bloğunu yürütmesi ve öğeyi mümkün olan en kısa zamanda yürütülecek komut dizisi kümesinden kaldırması gerekir.

Aksi takdirde , diğer komut dosyaları zaten yürütülüyor olsa bile, kullanıcı aracısı komut dosyası bloğunu derhal yürütmelidir.


Javascript modülü komut dosyalarına ne dersiniz type="module"?

Javascript artık aşağıdaki gibi sözdizimi ile modül yükleme desteği sunuyor:

<script type="module">
  import {addTextToBody} from './utils.mjs';

  addTextToBody('Modules are pretty cool.');
</script>

Veya şu srcnitelikle:

<script type="module" src="http://somedomain.com/somescript.mjs">
</script>

İle birlikte type="module"olan tüm komut dosyalarına otomatik olarak deferöznitelik verilir . Bu, bunları sayfanın diğer yüklenmesiyle paralel olarak (satır içi değilse) indirir ve ardından sırayla çalıştırır, ancak ayrıştırıcı tamamlandıktan sonra.

Modül komut dosyalarına asyncsatır içi modül komut dosyalarını en kısa zamanda çalıştıracak, ayrıştırıcı tamamlanana kadar beklemeyecek ve asynckomut dosyasını diğer komut dosyalarına göre belirli bir sırada çalıştırmayı beklemeyecek özellik de verilebilir .

Bu makalede modül komut dosyaları da dahil olmak üzere farklı komut dosyası birleşimlerinin getirilmesini ve yürütülmesini gösteren oldukça kullanışlı bir zaman çizelgesi grafiği vardır: Javascript Modülü Yükleme .


Cevap için teşekkürler, ama sorun yazısıdır edilir dinamik araçlar sayfasına eklenen zaman uyumsuz olarak kabul edilir . Yoksa bu sadece <head>? Deneyimlerim de belge düzeninde yürütüldüklerini mi?
Bergi

@Bergi - Dinamik olarak eklenirse, zaman uyumsuzdur ve denetlemek için kod yazmadıkça yürütme sırası belirsizdir.
jfriend00

Sadece Kolink devletler ... tersini
Bergi

@Bergi - Tamam, async komut dosyalarının belirsiz bir sırada yüklendiğini söylemek için cevabımı değiştirdim. Herhangi bir sırayla yüklenebilirler. Ben olsaydım, Kolink'in her zaman olduğu gibi gözlemine güvenmezdim. Dinamik olarak eklenen bir komut dosyasının hemen çalıştırılması ve yüklenene kadar diğer komut dosyalarının çalışmasını engellemesi gerektiğini söyleyen hiçbir standart bilmiyorum. Tarayıcıya bağlı ve belki de çevresel faktörlere (betiğin önbelleğe alınmış olup olmadığı vb.) Bağımlı olmasını beklerim.
jfriend00

1
@RuudLenders - Bu tarayıcı uygulamasına bağlı. Kod etiketinin belgede daha önce karşılaşılması, ancak ile işaretlenmesi deferayrıştırıcıya, yürütmeyi hala ertelerken indirmeye daha erken başlama fırsatı verir. Aynı ana makineden çok sayıda komut dosyanız varsa, indirmeyi daha erken başlatmanın, sayfanızın beklediği (olmayan defer) aynı ana bilgisayardan (bant genişliği için rekabet ettikleri gibi) başkalarının indirilmesini gerçekten yavaşlatabileceğini unutmayın. bu iki ucu keskin bir kılıç olabilir.
jfriend00

13

Tarayıcı komut dosyalarını buldukları sıraya göre yürütür. Harici bir komut dosyasını çağırırsanız, komut dosyası yüklenip yürütülene kadar sayfa engellenir.

Bu gerçeği test etmek için:

// file: test.php
sleep(10);
die("alert('Done!');");

// HTML file:
<script type="text/javascript" src="test.php"></script>

Dinamik olarak eklenen komut dosyaları, belgeye eklenir eklenmez yürütülür.

Bu gerçeği test etmek için:

<!DOCTYPE HTML>
<html>
<head>
    <title>Test</title>
</head>
<body>
    <script type="text/javascript">
        var s = document.createElement('script');
        s.type = "text/javascript";
        s.src = "link.js"; // file contains alert("hello!");
        document.body.appendChild(s);
        alert("appended");
    </script>
    <script type="text/javascript">
        alert("final");
    </script>
</body>
</html>

Uyarıların sırası "eklenir" -> "merhaba!" -> "son"

Bir komut dosyasında henüz ulaşılmayan bir öğeye erişmeye çalışırsanız (örnek <script>do something with #blah</script><div id="blah"></div>:) bir hata alırsınız.

Genel olarak, evet harici komut dosyaları ekleyebilir ve sonra işlevlerine ve değişkenlerine erişebilirsiniz, ancak yalnızca geçerli <script>etiketten çıkıp yeni bir tane başlatırsanız.


Bu davranışı teyit edebilirim. Ancak geri bildirim sayfalarımızda, yalnızca test.php önbelleğe alındığında çalışabileceğine dair ipuçları var. Bununla ilgili spesifikasyon / referans bağlantısı biliyor musunuz?
Bergi

4
link.js engellemiyor. Uzun bir indirme süresi simüle etmek için php birine benzer bir komut dosyası kullanın.
1983

14
Bu cevap yanlış. "Dinamik olarak eklenen komut dosyaları belgeye eklenir eklenmez yürütülür" her zaman böyle olmaz. Bazen bu doğrudur (örneğin Firefox'un eski sürümleri için), ancak genellikle değildir. Jfriend00'ün cevabında belirtildiği gibi icra emri kesin değildir.
Fabio Beltramini

1
Komut dosyalarının satır içi olup olmadıklarına bakılmaksızın sayfada göründükleri sırayla hariç tutulması mantıklı değildir. Öyleyse neden Google etiket yöneticisi snippet'i ve gördüğüm diğer pek çok sayfadaki tüm komut dosyası etiketlerinin üstüne yeni bir komut dosyası eklemek için kodunuz olsun ki? Yukarıdaki komut dosyaları kesinlikle yüklenmişse bunu yapmak mantıklı olmaz ?? yoksa bir şey mi kaçırıyorum.
user3094826


2

Birçok seçeneği test ettikten sonra, aşağıdaki basit çözümün dinamik olarak yüklenmiş komut dosyalarını tüm modern tarayıcılara eklendiği sırada yüklediğini gördüm

loadScripts(sources) {
    sources.forEach(src => {
        var script = document.createElement('script');
        script.src = src;
        script.async = false; //<-- the important part
        document.body.appendChild( script ); //<-- make sure to append to body instead of head 
    });
}

loadScripts(['/scr/script1.js','src/script2.js'])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.