web-dev-qa-db-ja.com

現在実行中のスクリプトをロードしたスクリプトタグを参照するにはどうすればよいですか?

現在実行中のJavaScriptをロードしたスクリプト要素を参照するにはどうすればよいですか?

状況は次のとおりです。最初に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>

「scripts.js」には、他のスクリプトをオンデマンドでロードできるようにする必要があるスクリプトがあります。 HEAD要素のレンダリングが完了していないため、HEADタグを参照せずに新しいスクリプトを追加する必要があるため、通常の方法ではうまくいきません。

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

私がやりたいのは、現在のスクリプトをロードしたスクリプト要素を参照して、動的にロードされた新しいスクリプトタグをDOMの後に追加できるようにすることです。

<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>
258
geuis

現在のスクリプト要素を取得する方法:

1. document.currentScriptを使用します

document.currentScript は、スクリプトが現在処理されている<script>要素を返します。

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

利点

  • シンプルかつ明示的。信頼性のある。
  • スクリプトタグを変更する必要はありません
  • 非同期スクリプト(deferasync)で動作します
  • 動的に挿入されたスクリプトで動作します

問題点

  • 古いブラウザとIEでは動作しません。
  • モジュール<script type="module">では機能しません

2. IDでスクリプトを選択します

スクリプトにid属性を与えると、 document.getElementById() を使用して内部からidで簡単に選択できます。

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

利点

  • シンプルかつ明示的。信頼性のある。
  • ほぼ普遍的にサポート
  • 非同期スクリプト(deferasync)で動作します
  • 動的に挿入されたスクリプトで動作します

問題点

  • スクリプトタグにカスタム属性を追加する必要があります
  • id属性は、一部のEdgeの場合、一部のブラウザーでスクリプトの動作がおかしい

3. data-*属性を使用してスクリプトを選択します

スクリプトに data-* 属性を指定すると、内部から簡単に選択できます。

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

これには、以前のオプションに比べて利点がほとんどありません。

利点

  • シンプルかつ明示的。
  • 非同期スクリプト(deferasync)で動作します
  • 動的に挿入されたスクリプトで動作します

問題点

  • スクリプトタグにカスタム属性を追加する必要があります
  • HTML5、およびquerySelector()はすべてのブラウザーに準拠していません
  • id属性を使用するよりも広くサポートされていません
  • id Edgeケースで<script>を回避します。
  • 別の要素がページ上で同じデータ属性と値を持つ場合、混乱する可能性があります。

4. srcでスクリプトを選択します

データ属性を使用する代わりに、セレクタを使用してソースごとにスクリプトを選択できます。

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

Embed.jsで:

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

利点

  • 信頼性のある
  • 非同期スクリプト(deferasync)で動作します
  • 動的に挿入されたスクリプトで動作します
  • カスタム属性やIDは不要です

問題点

  • ローカルスクリプトに対してnotは機能しますか
  • 開発や本番などのさまざまな環境で問題が発生します
  • 静的で壊れやすい。スクリプトファイルの場所を変更するには、スクリプトを変更する必要があります
  • id属性を使用するよりも広くサポートされていません
  • 同じスクリプトを2回ロードすると問題が発生します

5.すべてのスクリプトをループして、必要なスクリプトを見つけます

また、すべてのスクリプト要素をループして、それぞれを個別にチェックして、必要な要素を選択することもできます。

<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>

これにより、属性でquerySelector()を十分にサポートしていない古いブラウザーで以前の両方の手法を使用できます。例えば:

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

これは、どのアプローチをとっても利点と問題を継承しますが、querySelector()に依存しないため、古いブラウザーでも機能します。

6.最後に実行されたスクリプトを取得する

スクリプトは連続して実行されるため、最後のスクリプト要素は現在実行中のスクリプトであることが非常に多くなります。

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

利点

  • シンプル。
  • ほぼ普遍的にサポート
  • カスタム属性やIDは不要です

問題点

  • notは非同期スクリプト(deferasync)で動作しますか
  • notは動的に挿入されたスクリプトでは機能しますか
572
brice

スクリプトは連続して実行されるため、現在実行されているスクリプトタグは常にそれまでのページの最後のスクリプトタグです。したがって、スクリプトタグを取得するには、次のようにします。

var scripts = document.getElementsByTagName( 'script' );
var thisScriptTag = scripts[ scripts.length - 1 ];
87
Coffee Bite

おそらく最も簡単なことは、スクリプトタグにid属性を指定することです。

11
Greg

スクリプトは、「遅延」属性も「非同期」属性もない場合にのみ順次実行されます。スクリプトタグの可能なID/SRC/TITLE属性の1つを知ることは、それらのケースでも機能する可能性があります。したがって、GregとJustinの両方の提案は正しいです。

WHATWGリストにはdocument.currentScriptの提案が既にあります。

EDIT:Firefox> 4はすでにこの非常に便利なプロパティを実装していますが、前回チェックしたIE11では使用できず、Chrome 29およびSafari 8でのみ使用できます。

EDIT:「document.scripts」コレクションについて言及した人はいませんでしたが、現在実行中のスクリプトを取得するためのクロスブラウザーの代替手段として、次のものが適していると思います。

var me = document.scripts[document.scripts.length -1];
10
Diego Perini

document.CurrentScriptが存在する場合はそれを活用し、IDによるスクリプトの検索にフォールバックするポリフィルを少し紹介します。

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

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

これをすべてのスクリプトタグの先頭に含めると、どのスクリプトタグが起動されているかを一貫して知ることができ、非同期コールバックのコンテキストでスクリプトタグを参照することもできると思います。

テストされていないので、他の人に試してみてください。

9
Art Lawry

ページの読み込み時と、JavaScriptタグ(例:ajax)でスクリプトタグが追加されたときに機能する必要があります。

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

非同期および遅延スクリプトを処理する方法は、onloadハンドラーを活用することです。すべてのスクリプトタグに対してonloadハンドラーを設定し、最初に実行するタグを自分のものにします。

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);
});
3
Pete Blois

スクリプトを取得するには、現在使用しているスクリプトをロードしている

var thisScript = document.currentScript;

スクリプトの先頭に参照を保持する必要があるため、後で呼び出すことができます

var url = thisScript.src

次の簡単な手順に従って、現在実行中のスクリプトブロックへの参照を取得します。

  1. スクリプトブロック内にランダムな一意の文字列を配置します(各スクリプトブロックで一意/異なる必要があります)
  2. Document.getElementsByTagName( 'script')の結果を反復処理し、それぞれのコンテンツ(innerText/textContentプロパティから取得)から一意の文字列を探します。

例(ABCDE345678は一意のID)

<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>

ところで、あなたの場合、古い形式のdocument.write()メソッドを使用して別のスクリプトを含めることができます。 DOMがまだレンダリングされていないことを述べたように、ブラウザーは常に線形シーケンスでスクリプトを実行するという事実を活用できます(後でレンダリングされる遅延スクリプトを除く)。したがって、ドキュメントの残りの部分はまだ「存在しません」。 document.write()を介して書き込むものはすべて、呼び出し元スクリプトの直後に配置されます。

元のHTMLページの例

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

script.jsのコンテンツ

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

レンダリング後、DOM構造は次のようになります。

HEAD
  SCRIPT script.js
  SCRIPT inserted.js
  SCRIPT otherscript.js
BODY
2
Ferdinand Liu

このアルゴリズムを検討してください。スクリプトがロードされたら(複数の同一のスクリプトがある場合)、document.scriptsを調べ、正しい「src」属性を持つ最初のスクリプトを見つけて保存し、データ属性または一意のclassNameで「訪問済み」としてマークします。

次のスクリプトが読み込まれたら、document.scriptsを再度スキャンし、既に訪問済みとしてマークされているスクリプトを渡します。そのスクリプトの最初の未訪問のインスタンスを取得します。

これは、同一のスクリプトがロードされた順序で、頭から体、上から下、同期から非同期に実行される可能性が高いことを前提としています。

(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;
  }
})();

これにより、特別な属性でマークされていない最初に一致するスクリプトのすべてのスクリプトがスキャンされます。

次に、そのノードが見つかった場合は、その後のスキャンで選択されないようにデータ属性でマークします。これは、ノードが再訪問を防ぐために「訪問済み」とマークされる可能性があるグラフトラバーサルBFSおよびDFSアルゴリズムに似ています。

2
LSOJ

次のコードは、最も一貫性があり、パフォーマンスが高く、シンプルであることがわかりました。

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);
0
Travis Tidwell

スクリプトのファイル名を推測できる場合は、それを見つけることができます。これまでのところ、Firefoxで次の機能を実際にテストしただけです。

  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');
0
Justin Love

スクリプトの名前(または少なくともその一部)を知っている場合、別の簡単な方法があります。

document.querySelector('script[src*="<scriptname>.js"]')

これはIE11でも機能します。

0