Bagaimana saya bisa mereferensikan tag skrip yang memuat skrip yang saat ini mengeksekusi?

303

Bagaimana saya bisa mereferensikan elemen skrip yang memuat javascript yang sedang berjalan?

Inilah situasinya. Saya memiliki skrip "master" yang dimuat tinggi di halaman, hal pertama di bawah tag HEAD.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="scripts.js"></script>

Ada skrip di "scripts.js" yang harus dapat melakukan pemuatan skrip lain berdasarkan permintaan. Metode normal tidak cukup berfungsi untuk saya karena saya perlu menambahkan skrip baru tanpa merujuk tag HEAD, karena elemen HEAD belum selesai render:

document.getElementsByTagName('head')[0].appendChild(v);

Yang ingin saya lakukan adalah mereferensikan elemen skrip yang memuat skrip saat ini sehingga saya kemudian dapat menambahkan tag skrip baru yang dimuat secara dinamis ke dalam DOM setelahnya.

<script type="text/javascript" src="scripts.js"></script>
loaded by scripts.js--><script type="text/javascript" src="new_script1.js"></script>
loaded by scripts.js --><script type="text/javascript" src="new_script2.js"></script>
Shog9
sumber
1
Sebuah kata peringatan: memodifikasi DOM saat masih memuat akan menyebabkan Anda terluka di IE6 & IE7 . Anda akan lebih baik menjalankan kode itu setelah memuat halaman.
Triptych
6
Sepertinya terserah pada caniuse sekarang: caniuse.com/#feat=document-currentscript
Tyler

Jawaban:

653

Cara mendapatkan elemen skrip saat ini:

1. Gunakan document.currentScript

document.currentScriptakan mengembalikan <script>elemen yang skripnya sedang diproses.

<script>
var me = document.currentScript;
</script>

Manfaat

  • Sederhana dan eksplisit. Andal.
  • Tidak perlu memodifikasi tag skrip
  • Bekerja dengan skrip asinkron ( defer& async)
  • Bekerja dengan skrip yang disisipkan secara dinamis

Masalah

  • Tidak akan berfungsi di browser dan IE yang lebih lama.
  • Tidak bekerja dengan modul <script type="module">

2. Pilih skrip berdasarkan id

Memberi script atribut id akan memungkinkan Anda dengan mudah memilihnya dengan id dari dalam menggunakan document.getElementById().

<script id="myscript">
var me = document.getElementById('myscript');
</script>

Manfaat

  • Sederhana dan eksplisit. Andal.
  • Hampir didukung secara universal
  • Bekerja dengan skrip asinkron ( defer& async)
  • Bekerja dengan skrip yang disisipkan secara dinamis

Masalah

  • Perlu menambahkan atribut khusus ke tag skrip
  • id atribut dapat menyebabkan perilaku aneh untuk skrip di beberapa browser untuk beberapa kasus tepi

3. Pilih skrip menggunakan data-*atribut

Dengan memberikan data-*atribut pada skrip, Anda dapat dengan mudah memilihnya dari dalam.

<script data-name="myscript">
var me = document.querySelector('script[data-name="myscript"]');
</script>

Ini memiliki sedikit manfaat dibandingkan opsi sebelumnya.

Manfaat

  • Sederhana dan eksplisit.
  • Bekerja dengan skrip asinkron ( defer& async)
  • Bekerja dengan skrip yang disisipkan secara dinamis

Masalah

  • Perlu menambahkan atribut khusus ke tag skrip
  • HTML5, dan querySelector()tidak memenuhi semua browser
  • Kurang banyak didukung daripada menggunakan idatribut
  • Akan bergaul <script>dengan idkasus tepi.
  • Mungkin bingung jika elemen lain memiliki atribut dan nilai data yang sama pada halaman.

4. Pilih skrip berdasarkan src

Alih-alih menggunakan atribut data, Anda dapat menggunakan pemilih untuk memilih skrip menurut sumber:

<script src="//example.com/embed.js"></script>

Di embed.js:

var me = document.querySelector('script[src="//example.com/embed.js"]');

Manfaat

  • Andal
  • Bekerja dengan skrip asinkron ( defer& async)
  • Bekerja dengan skrip yang disisipkan secara dinamis
  • Tidak diperlukan atribut atau id khusus

Masalah

  • Apakah tidak bekerja untuk script lokal
  • Akan menyebabkan masalah di lingkungan yang berbeda, seperti Pengembangan dan Produksi
  • Statis dan rapuh. Mengubah lokasi file skrip akan membutuhkan modifikasi skrip
  • Kurang banyak didukung daripada menggunakan idatribut
  • Akan menyebabkan masalah jika Anda memuat skrip yang sama dua kali

5. Ulangi semua skrip untuk menemukan yang Anda inginkan

Kami juga dapat mengulangi setiap elemen skrip dan memeriksa masing-masing satu per satu untuk memilih yang kami inginkan:

<script>
var me = null;
var scripts = document.getElementsByTagName("script")
for (var i = 0; i < scripts.length; ++i) {
    if( isMe(scripts[i])){
      me = scripts[i];
    }
}
</script>

Ini memungkinkan kami menggunakan kedua teknik sebelumnya di browser lama yang tidak mendukung querySelector()dengan baik dengan atribut. Sebagai contoh:

function isMe(scriptElem){
    return scriptElem.getAttribute('src') === "//example.com/embed.js";
}

Ini mewarisi manfaat dan masalah dari pendekatan apa pun yang diambil, tetapi tidak mengandalkan querySelector()sehingga akan bekerja di browser lama.

6. Dapatkan skrip yang dieksekusi terakhir

Karena skrip dieksekusi secara berurutan, elemen skrip terakhir akan sangat sering menjadi skrip yang sedang berjalan:

<script>
var scripts = document.getElementsByTagName( 'script' );
var me = scripts[ scripts.length - 1 ];
</script>

Manfaat

  • Sederhana.
  • Hampir didukung secara universal
  • Tidak diperlukan atribut atau id khusus

Masalah

  • Apakah tidak bekerja dengan script asynchronous ( defer& async)
  • Apakah tidak bekerja dengan script dimasukkan secara dinamis
brice
sumber
4
Ini seharusnya jawabannya.
Royi Namir
1
Setuju dengan @RoyiNamir. Ini jawaban terbaik.
Hans
27
Terima kasih teman-teman, tetapi Anda tahu saya menjawab 4 tahun setelah jawaban diterima, benar :)
brice
5
"document.currentScript" tidak berfungsi untuk saya dengan skrip dinamis yang dimuat, mengembalikan nol di chrome / firefox terbaru, "skrip yang terakhir dieksekusi" berfungsi ok
xwild
1
tidak bekerja ketika scriptberada dalam templatedimasukkan dalam bayangan DOM
Supersharp
86

Karena skrip dieksekusi secara berurutan, tag skrip yang saat ini dieksekusi selalu menjadi tag skrip terakhir pada halaman sampai saat itu. Jadi, untuk mendapatkan tag skrip, Anda dapat melakukan:

var scripts = document.getElementsByTagName( 'script' );
var thisScriptTag = scripts[ scripts.length - 1 ];
Gigitan Kopi
sumber
3
Ini sederhana dan elegan. Ada contohnya di Google Charts / Visualisasi API baru jika Anda membongkar javascript. Mereka memuat data JSON dari dalam tag skrip, lihat: ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js
Jason Thrasher
1
Ini adalah ide yang bagus, dan biasanya bekerja untuk saya Tetapi saya harus menambahkan bahwa ada kalanya saya menemukannya mengembalikan referensi ke skrip yang berbeda. Tidak yakin mengapa - belum dapat melacaknya. Akibatnya, saya biasanya menggunakan metode yang berbeda, misalnya, saya membuat kode nama file skrip, dan mencari tag skrip dengan nama file itu.
Ken Smith
53
Satu contoh yang bisa saya pikirkan di mana ini mungkin mengembalikan hasil yang salah adalah ketika tag skrip ditambahkan ke DOM secara tidak sinkron.
Gigitan Kopi
9
Ya ini dapat memiliki hasil yang tidak terduga sehingga Anda dapat mencoba menggunakan pemilih sebagai gantinya: $ ('script [src * = "/ mysource.js"]') ???
Jason Sebring
7
Ini tidak berfungsi ketika Anda memiliki skrip yang dimuat setelah halaman dimuat. Anda mungkin tidak akan mendapatkan tag yang tepat.
ThemeZ
11

Mungkin hal termudah untuk dilakukan adalah memberikan idatribut tag tag Anda .

Greg
sumber
2
Meskipun Anda benar, ada banyak kasus di mana pertanyaan OP valid, pasangan adalah: 1) ketika Anda merangkak 2) ketika Anda bekerja dengan DOM klien, dan dia tidak mau berubah
nichochar
10

Script dijalankan secara berurutan hanya jika mereka tidak memiliki atribut "penangguhan" atau "async". Mengetahui salah satu atribut ID / SRC / TITLE yang mungkin dari tag script dapat bekerja juga dalam kasus-kasus itu. Jadi saran Greg dan Justin benar.

Sudah ada proposal untuk document.currentScriptdi daftar WHATWG.

EDIT : Firefox> 4 sudah menerapkan properti yang sangat berguna ini tetapi tidak tersedia di IE11 yang terakhir saya periksa dan hanya tersedia di Chrome 29 dan Safari 8.

EDIT : Tidak ada yang menyebutkan koleksi "document.scripts" tapi saya percaya bahwa yang berikut ini mungkin merupakan alternatif lintas browser yang baik untuk mendapatkan skrip yang sedang berjalan:

var me = document.scripts[document.scripts.length -1];
Diego Perini
sumber
1
Ini document.script bukan document.script
Moritz
9

Berikut adalah sedikit polyfill yang memanfaatkan document.CurrentScriptjika ada dan kembali menemukan skrip dengan ID.

<script id="uniqueScriptId">
    (function () {
        var thisScript = document.CurrentScript || document.getElementByID('uniqueScriptId');

        // your code referencing thisScript here
    ());
</script>

Jika Anda memasukkan ini di bagian atas setiap tag skrip saya percaya Anda akan dapat secara konsisten mengetahui tag skrip mana yang sedang dipecat, dan Anda juga akan dapat mereferensikan tag skrip tersebut dalam konteks panggilan balik asinkron.

Belum diuji, jadi tinggalkan umpan balik untuk orang lain jika Anda mencobanya.

Lawry Seni
sumber
The idatribut tidak valid dalam scriptelemen sekalipun. Jenis masalah apa yang bisa dihasilkan oleh pendekatan ini?
nr
1
@ nr - Tidak, semua elemen dapat memiliki idatribut. id,, classdan slotdidefinisikan pada level DOM, bukan level HTML. Jika Anda pergi ke atribut global dalam HTML dan menggulir melewati daftar, Anda akan menemukan "Standar DOM mendefinisikan persyaratan agen pengguna untuk atribut kelas, id, dan slot untuk setiap elemen di namespace apa pun." diikuti oleh "Atribut class, id, dan slot dapat ditentukan pada semua elemen HTML." Spesifikasi DOM membahasnya di sini .
TJ Crowder
6

Ini harus berfungsi saat memuat halaman dan ketika tag skrip ditambahkan dengan javascript (mis. Dengan ajax)

<script id="currentScript">
var $this = document.getElementById("currentScript");
$this.setAttribute("id","");
//...
</script>
David Callizaya
sumber
3

Ikuti langkah-langkah sederhana ini untuk mendapatkan referensi ke blok skrip eksekusi saat ini:

  1. Masukkan beberapa string unik acak ke dalam blok skrip (harus unik / berbeda di setiap blok skrip)
  2. Iterate hasil dari document.getElementsByTagName ('script'), mencari string unik dari setiap konten mereka (diperoleh dari properti innerText / textContent).

Contoh (ABCDE345678 adalah ID unik) :

<script type="text/javascript">
var A=document.getElementsByTagName('script'),i=count(A),thi$;
for(;i;thi$=A[--i])
  if((thi$.innerText||thi$.textContent).indexOf('ABCDE345678'))break;
// Now thi$ is refer to current script block
</script>

btw, untuk kasus Anda, Anda cukup menggunakan metode document.write () kuno untuk memasukkan skrip lain. Seperti yang Anda sebutkan bahwa DOM belum dirender, Anda dapat memanfaatkan fakta bahwa browser selalu menjalankan skrip dalam urutan linier (kecuali untuk yang ditangguhkan yang akan dirender nanti), sehingga sisa dokumen Anda masih "tidak ada". Apa pun yang Anda tulis melalui document.write () akan ditempatkan tepat setelah skrip penelepon.

Contoh halaman HTML asli :

<!doctype html>
<html><head>
<script src="script.js"></script>
<script src="otherscript.js"></script>
<body>anything</body></html>

Konten script.js :

document.write('<script src="inserted.js"></script>');

Setelah diberikan, struktur DOM akan menjadi:

HEAD
  SCRIPT script.js
  SCRIPT inserted.js
  SCRIPT otherscript.js
BODY
Ferdinand Liu
sumber
Tampaknya ini hanya berfungsi untuk skrip inline, bukan skrip eksternal. Dalam kasus terakhir semua properti innerText, teks, dan textContent kosong.
Jos de Jong
3

Suatu pendekatan untuk berurusan dengan skrip async & deferred adalah untuk memanfaatkan penangan onload- menetapkan penangan onload untuk semua tag skrip dan yang pertama yang dijalankan harus menjadi milik Anda.

function getCurrentScript(callback) {
  if (document.currentScript) {
    callback(document.currentScript);
    return;
  }
  var scripts = document.scripts;
  function onLoad() {
    for (var i = 0; i < scripts.length; ++i) {
      scripts[i].removeEventListener('load', onLoad, false);
    }
    callback(event.target);
  }
  for (var i = 0; i < scripts.length; ++i) {
    scripts[i].addEventListener('load', onLoad, false);
  }
}

getCurrentScript(function(currentScript) {
  window.console.log(currentScript.src);
});
Pete Blois
sumber
3

Untuk mendapatkan skrip, skrip yang saat ini dimuat dapat Anda gunakan

var thisScript = document.currentScript;

Anda harus menyimpan referensi di awal skrip Anda, sehingga Anda dapat menelepon nanti

var url = thisScript.src
Peter Lakatos - appnomads
sumber
2

Pertimbangkan algoritma ini. Ketika skrip Anda dimuat (jika ada beberapa skrip identik), lihat melalui document.scripts, cari skrip pertama dengan atribut "src" yang benar, dan simpan dan tandai sebagai 'dikunjungi' dengan atribut data atau className unik.

Saat skrip berikutnya dimuat, pindai lagi melalui dokumen.kripsinya, lewati setiap skrip yang sudah ditandai sebagai dikunjungi. Ambil contoh skrip yang belum dikunjungi pertama kali.

Ini mengasumsikan bahwa skrip identik kemungkinan akan mengeksekusi dalam urutan di mana mereka dimuat, dari head ke body, dari atas ke bawah, dari sinkron ke asinkron.

(function () {
  var scripts = document.scripts;

  // Scan for this data-* attribute
  var dataAttr = 'data-your-attribute-here';

  var i = 0;
  var script;
  while (i < scripts.length) {
    script = scripts[i];
    if (/your_script_here\.js/i.test(script.src)
        && !script.hasAttribute(dataAttr)) {

        // A good match will break the loop before
        // script is set to null.
        break;
    }

    // If we exit the loop through a while condition failure,
    // a check for null will reveal there are no matches.
    script = null;
    ++i;
  }

  /**
   * This specific your_script_here.js script tag.
   * @type {Element|Node}
   */
  var yourScriptVariable = null;

  // Mark the script an pass it on.
  if (script) {
    script.setAttribute(dataAttr, '');
    yourScriptVariable = script;
  }
})();

Ini akan memindai seluruh skrip untuk skrip pencocokan pertama yang tidak ditandai dengan atribut khusus.

Kemudian tandai simpul itu, jika ditemukan, dengan atribut data sehingga pemindaian selanjutnya tidak akan memilihnya. Ini mirip dengan algoritma BFS dan DFS traversal grafik di mana node dapat ditandai sebagai 'dikunjungi' untuk mencegah kunjungan kembali.

LSOJ
sumber
Selamat datang di Stack Overflow. Apakah Anda ingin memasukkan beberapa kode dengan algoritme?
Gary99
Thar you go, @ Gary99
LSOJ
0

Saya punya ini, yang bekerja di FF3, IE6 & 7. Metode-metode dalam skrip yang dimuat berdasarkan permintaan tidak tersedia sampai pemuatan halaman selesai, tetapi ini masih sangat berguna.

//handle on-demand loading of javascripts
makescript = function(url){
    var v = document.createElement('script');
    v.src=url;
    v.type='text/javascript';

    //insertAfter. Get last <script> tag in DOM
    d=document.getElementsByTagName('script')[(document.getElementsByTagName('script').length-1)];
    d.parentNode.insertBefore( v, d.nextSibling );
}

sumber
0

Jika Anda dapat menganggap nama file skrip, Anda dapat menemukannya. Saya hanya benar-benar menguji fungsi berikut di Firefox sejauh ini.

  function findMe(tag, attr, file) {
    var tags = document.getElementsByTagName(tag);
    var r = new RegExp(file + '$');
    for (var i = 0;i < tags.length;i++) {
      if (r.exec(tags[i][attr])) {
        return tags[i][attr];
      }
    }
  };
  var element = findMe('script', 'src', 'scripts.js');
Justin Love
sumber
1
Sangat ketinggalan jaman. Ini dapat dilakukan dengan kueriSelektor, oneliner sederhana!
Fabian von Ellerts
-1

Saya telah menemukan kode berikut ini sebagai yang paling konsisten, berkinerja, dan sederhana.

var scripts = document.getElementsByTagName('script');
var thisScript = null;
var i = scripts.length;
while (i--) {
  if (scripts[i].src && (scripts[i].src.indexOf('yourscript.js') !== -1)) {
    thisScript = scripts[i];
    break;
  }
}
console.log(thisScript);
Travis Tidwell
sumber