24

エラーがスローされた場合の Javascript の実行に関する重要な事実を学びました。これについて結論を出す前に、自分が正しいかどうかを確認したほうがよいでしょう。

2 つのスクリプトを含む HTML ページがあるとします。

<script src="script1.js" />
<script src="script2.js" />

スクリプト 1:

doSomething();

スクリプト 2:

doSomeOtherThing();

これにより、事実上、1 つのスクリプトが 1 つのユニットとして処理されます。

doSomething();
doSomeOtherThing();

特に、doSomethingエラーがスローされると、実行が中断されます。「script2」は実行されません。

これは私の「レッスン 1」です。これは別のインクルード ファイルであるため、script1 の影響を受けないと思われるかもしれません。しかし、そうです。 => 以下の「最新の更新」を参照してください


ここで、script2 を次のように変更するとします (上のどこかに jQuery が含まれていると仮定します)。

$(document).ready({ doSomeOtherThing(); });

script2 の前にスクリプトを配置します。

<script src="script2.js" />
<script src="script1.js" />

実行の順序は、事実上、「doSomething()」の後に (いつか)「doSomeOtherThing()」が続きます。

ただし、2 つの「ユニット」で実行されます。

  • doSomethingドキュメントの Java スクリプトの一部として早期に実行される
  • doSomeOtherThingdocument.ready イベントが処理されるときに実行されます。

doSomeOtherThing例外がスローされた場合、2 番目の処理「ユニット」は中断されません。

(この用語の使用は控えますthread。通常、すべてのスクリプトは同じスレッドで実行されると考えているためです。より正確には、これはブラウザーに依存する可能性があります。)

したがって、私の教訓 2 : JavaScript エラーによって後続のスクリプトの実行が妨げられる場合がありますが、イベント ループは停止しません。


結論 1

$(document).ready()成功するために他のスクリプトとは独立して実行する必要がある JavaScript コードのチャンクを定義するのに優れた仕事をします。

または、言い換えると、JavaScript の一部があり、他のスクリプトが失敗した場合でも確実に実行されるようにしたい場合は、$(document).ready().

これは、スクリプトがドキュメントが完全に読み込まれることに依存している場合にのみイベントを使用していたという点で、私にとっては新しいことです。


結論2

さらに一歩進んで、すべてのスクリプトが実行のために「キューに入れられる」ことを確認するために、すべてのスクリプトを 内にラップすることは、アーキテクチャ上の適切な決定である可能性があります。上記の 2 番目の例では、例 1$(document).ready()のように ifがscript2.jsに含まれていました。 script1.js

<script src="script1.js" />
<script src="script2.js" />

script1.js にエラーがあると、関数が実行されないdoSomeOtherThing()ため、 を登録することさえできません。$(document).ready()

ただし、script1.js$(document).ready()も使用すると、それは起こりません。

$(document).ready(function() { doSomething(); });
$(document).ready(function() { doSomeOtherThing(); });

両方の行が実行されます。その後、イベント ループが実行doSomethingされて中断しますが、doSomeOtherThing影響はありません。

そうするもう 1 つの理由は、ページをレンダリングするスレッドができるだけ早く戻ることができ、イベント ループを使用してコード実行をトリガーできることです。


批評 / 質問:

  • 私は間違っていましたか?
  • コードの一部をすぐに実行する必要がある、つまりイベントにラップしないことが必要な理由は何ですか?
  • パフォーマンスに大きな影響を与えますか?
  • ドキュメント準備完了イベントを使用するのではなく、同じことを達成するための別の/より良い方法はありますか?
  • すべてのスクリプトがコードをイベント ハンドラーとして登録するだけの場合、スクリプトの実行順序を定義できますか? イベント ハンドラーは、登録された順序で実行されますか?

有益なコメントをお待ちしております!

遅い更新:

Briguy37 が正しく指摘したように、私の観察はそもそも間違っていたに違いありません。(「私は間違っていましたか-はい!」)。彼の簡単な例を取り上げると、すべての主要なブラウザーで再現でき、IE8 でさえ、script1 がエラーをスローしても script2 が実行されます。

それでも@Marcelloの素晴らしい答えは、実行スタックなどの概念について洞察を得るのに役立ちます。2つのスクリプトのそれぞれが別々の実行スタックで実行されるようです。

4

3 に答える 3

16

JS がエラーを処理する方法は、JS がスクリプトを処理する方法によって異なります。スレッドとはまったく (またはほとんど) 関係ありません。そのため、最初にコードを通じて JS がどのように機能するかを考える必要があります。

まず、JS はすべてのスクリプト ファイル/ブロックを順番に読み込みます (この時点では、コードはテキストとしてのみ表示されます)。

JS がそのテキストブロックの解釈を開始し、それらを実行可能なコードにコンパイルします。構文エラーが見つかった場合、JS はコンパイルを停止し、次のスクリプトに進みます。このプロセスでは、JS はすべてのスクリプト ブロック/ファイルを個別のエンティティとして処理します。そのため、スクリプト 1 の構文エラーによってスクリプト 2 の実行が中断されるとは限りません。コードは解釈およびコンパイルされますが、この時点では実行されないため、throw new Errorコマンド実行を中断しません。

すべてのスクリプト ファイル/ブロックがコンパイルされた後、JS はコードを調べ (コード内の最初のコード ファイル/ブロックから開始)、いわゆる実行スタックを構築します (関数 a は関数 b を呼び出し、関数 d および c を呼び出します.... )、指定された順序で実行します。任意の時点で処理エラーが発生した場合、またはプログラムによってスローされた場合 ( throw new Error('fail'))、そのスタックの実行全体が停止し、JS はそのスタックの先頭から先頭に戻り、次の可能なスタックの実行から開始します。

そうは言っても、script1.js でエラーが発生した後も onload 関数が実行される理由は、新しいスレッドや何かが原因ではなく、単にイベントが別の実行スタックを構築するためであり、JS は次の後にジャンプできます。前回の実行スタックでエラーが発生しました。

あなたの質問に来て:

コードの一部をすぐに実行する必要がある、つまりイベントにラップしないことが必要な理由は何ですか?

Web アプリケーションでコードを「すぐに」呼び出さないことをお勧めします。ベスト プラクティスは、onload イベント内で呼び出される単一の入り口をアプリケーションに用意することです。

$(document).ready(function () {App.init()});

ただし、これはエラー処理などとは関係ありません。if(typeof myValue !== 'undefined')エラー処理自体は、潜在的なエラーが予想される場合に、条件分岐または try/catch/finally ブロックを使用してコード内で確実に実行する必要があります。これにより、catch ブロック内で 2 番目の方法を試すか、finally でエラーを適切に処理する機会も得られます。

アプリケーションイベント駆動型を構築できる場合 (もちろんエラー処理の理由ではない)、そうしてください。JS はイベント ドリブン言語であり、イベント ドリブン コードを記述するときに、JS を最大限に活用できます...

パフォーマンスに大きな影響を与えますか?

イベント駆動型のアプローチは、アプリケーションのパフォーマンスをさらに向上させ、同時により強固なものにします。イベント ドリブン コードは、内部処理ロジックの量を減らすのに役立ちます。

ドキュメント準備完了イベントを使用するのではなく、同じことを達成するための別の/より良い方法はありますか?

前述のとおり: try/catch/finally

すべてのスクリプトがコードをイベント ハンドラーとして登録するだけの場合、スクリプトの実行順序を定義できますか? イベント ハンドラーは、登録された順序で実行されますか?

同じオブジェクトに同じイベントを登録すると、順序が保持されます。

于 2012-10-25T16:02:34.560 に答える
9

それらが 1 つのスクリプトとして実行されるという最初の仮定は正しくありません。Script1 がエラーをスローしても、Script2 は引き続き実行されます。簡単なテストでは、次のファイル構造を実装します。

-anyFolder
--test.html
--test.js
--test2.js

test.html の内容:

<html>
   <head>
       <script type="text/javascript" src="test.js"></script>
       <script type="text/javascript" src="test2.js"></script>
   </head>
</html>

test.js の内容:

console.log('test before');
throw('foo');
console.log('test after');

test2.js の内容:

console.log('test 2');

(コンソールで) test.html を開いたときの出力:

test before test.js:1
Uncaught foo test.js:2
test 2 

このテストから、test.js がエラーをスローしても、test2.js は引き続き実行されることがわかります。ただし、エラーが発生した後、test.js は実行を停止します。

于 2012-10-25T13:16:55.167 に答える
3

構文エラーについてはわかりませんが、 を使用try {} catch(e) {}してエラーをキャッチし、残りのコードを実行し続けることができます。

最後まで実行されません

var json = '{"name:"John"'; // Notice the missing curly bracket }

// This probably will throw an error, if the string is buggy
var obj = JSON.parse(json);

alert('This will NOT run');

最後まで走ります

var json = '{"name:"John"'; // Notice the missing curly bracket }

// But like this you can catch errors
try {
  var obj = JSON.parse(json);
} catch (e) {
  // Do or don'
}

alert('This will run');

アップデート

エラーが発生した場合に残りのコードが確実に実行されるようにする方法を示したかっただけです。

コードの一部をすぐに実行する、つまりイベントにラップしないことが必要になる理由は何ですか?

パフォーマンス。そのようなイベントはすべて、イベント キューをいっぱいにします。それほど傷つくわけではありませんが、必要ではないだけです... 今すぐできるのに、なぜ後でやる必要があるのでしょうか。たとえば、ブラウザの検出などです。

パフォーマンスに大きな影響を与えますか?

これを 1 秒間に何度も実行している場合は、はい。

ドキュメント準備完了イベントを使用するのではなく、同じことを達成するための別の/より良い方法はありますか?

はい。上記の例を参照してください。

すべてのスクリプトがコードをイベント ハンドラーとして登録するだけの場合、スクリプトの実行順序を定義できますか? イベント ハンドラーは、登録された順序で実行されますか?

はい、私は彼らがそうであると確信しています。

于 2012-10-25T12:31:53.200 に答える