chi*_*oro 23 javascript error-handling jquery javascript-events
我刚刚学到了一个关于javascript执行的重要事实,如果出现错误的话.在我开始对此做出结论之前,我最好先验证一下我是否正确.
给定一个包含2个脚本的HTML页面:
<script src="script1.js" />
<script src="script2.js" />
Run Code Online (Sandbox Code Playgroud)
SCRIPT1:
doSomething();
Run Code Online (Sandbox Code Playgroud)
SCRIPT2:
doSomeOtherThing();
Run Code Online (Sandbox Code Playgroud)
这有效地导致单个脚本作为一个单元处理:
doSomething();
doSomeOtherThing();
Run Code Online (Sandbox Code Playgroud)
特别是,如果doSomething抛出错误,执行就会中断.'script2'永远不会被执行.
这是我的"第1课" - 人们可能会认为,因为它是一个单独包含的文件,所以它不受script1的影响.但它是. =>请参阅下面的"延迟更新"
现在,如果我们按如下方式更改script2(假设我们在上面的某处包含了jQuery):
$(document).ready({ doSomeOtherThing(); });
Run Code Online (Sandbox Code Playgroud)
并将脚本放在script2之前:
<script src="script2.js" />
<script src="script1.js" />
Run Code Online (Sandbox Code Playgroud)
执行的顺序实际上仍然是'doSome(()某些时候由'doSomeOtherThing()'执行的'doSomething()'.
但是它以两个"单位"执行:
doSomething 作为文档的java脚本的一部分提前执行doSomeOtherThing 在处理document.ready事件时执行.如果doSomeOtherThing抛出异常,它将不会破坏第二个处理"单元".
(我不使用该术语,thread因为我认为所有脚本通常由同一个线程执行,或者更确切地说,这可能取决于浏览器.)
所以,我的第2课:即使JavaScript错误可能会阻止任何后续脚本执行,它也不会停止事件循环.
结论1
$(document).ready() 在定义应该独立于任何其他脚本执行的JavaScript代码块方面做得很好.
或者,换句话说:如果你有一段JavaScript,并且想要确保即使其他脚本失败也能执行它,那么将它放在一个$(document).ready().
这对我来说是新的,因为如果脚本依赖于完全加载的文档,我只会使用该事件.
结论2
更进一步,将所有脚本包装在a中$(document).ready()以确保所有脚本都"排队"执行可能是一个很好的架构决策.另外,在上述第二示例中,如果script2.js被列入后 script1.js实施例1如下所示:
<script src="script1.js" />
<script src="script2.js" />
Run Code Online (Sandbox Code Playgroud)
script1.js中的错误会阻止doSomeOtherThing()甚至被注册,因为该$(document).ready()函数不会被执行.
但是,如果使用script1.js $(document).ready(),那也不会发生:
$(document).ready(function() { doSomething(); });
$(document).ready(function() { doSomeOtherThing(); });
Run Code Online (Sandbox Code Playgroud)
这两行都将被执行.然后,事件循环将执行doSomething哪个会中断,但doSomeOtherThing不会受到影响.
这样做的另一个原因是呈现页面的线程可以尽快返回,并且事件循环可以用于触发代码执行.
批评/问题:
期待任何有用的评论!
晚更新:
就像Briguy37正确指出的那样,我的观察一定是错误的.("我错了 - 是的!").以他的简单示例为例,我可以在所有主流浏览器中重现它,甚至在IE8中,即使script1抛出错误,也会执行script2.
仍然@ Marcello的伟大答案有助于深入了解执行堆栈的概念等.似乎两个脚本中的每一个都在一个单独的执行堆栈中执行.
Mar*_*one 16
JS处理错误的方式取决于JS处理脚本的方式.它与线程没有任何关系(或很少).因此,您必须首先考虑JS如何通过您的代码.
首先,JS会逐步读取每个脚本文件/块(此时您的代码只是看作文本).
比JS开始解释那些文本块并将它们编译成可执行代码.如果发现语法错误,JS将停止编译并继续执行下一个脚本.在这个过程中,JS将每个脚本块/文件作为分离的实体处理,这就是为什么脚本1中的语法错误不一定会破坏脚本2的执行.代码将被解释和编译,但此时不执行,所以throw new Error命令不会打破执行.
在编译完所有脚本文件/块之后,JS会遍历代码(从代码中的第一个代码文件/块开始)并构建一个所谓的执行堆栈(函数调用函数b调用函数d和c ....并按给定的顺序执行它.如果在任何时候发生处理错误或以编程方式抛出(throw new Error('fail')),则停止该堆栈的整个执行,并且JS返回到该堆栈的开头并开始执行下一个可能的堆栈.
也就是说,你的onload函数在script1.js中发生错误后仍然执行的原因,不是因为一个新的线程或其他东西而发生的,只是因为一个事件构建了一个单独的执行堆栈,JS可以跳转到上一个执行堆栈发生错误.
来你的问题:
有什么理由使得必须立即执行一段代码,即不将其包装到事件中?
我建议你在你的网络应用程序中根本没有"立即"调用代码.最佳实践是在应用程序中有一个入口点,在onload事件中调用
$(document).ready(function () {App.init()});
Run Code Online (Sandbox Code Playgroud)
然而,这与错误处理等无关.错误处理本身绝对应该在您的代码中使用条件if(typeof myValue !== 'undefined')或try/catch/finally块进行,您可能会遇到潜在的错误.这也让您有机会在catch块内尝试第二种方法,或者最终优雅地处理错误.
如果您可以构建应用程序事件驱动(当然不是出于错误处理的原因),请执行此操作.JS是一种事件驱动的语言,在编写事件驱动的代码时,你可以充分利用它...
它会显着影响性能吗?
一个事件驱动的方法将恕我直言,使您的应用程序表现更好,同时使其更加稳固.事件驱动的代码可以帮助您减少内部处理逻辑的数量,您只需要进入它.
有没有其他/更好的方法来实现相同而不是使用文档就绪事件?
如前所述:try/catch/finally
如果所有脚本只将其代码注册为事件处理程序,是否可以定义脚本的执行顺序?事件处理程序是按照它们注册的顺序执行的吗?
如果在同一对象上注册相同的事件,则会保留该顺序.
您首次假设它们作为一个脚本运行是不正确的.即使Script1抛出错误,Script2仍将执行.对于简单测试,请实现以下文件结构:
-anyFolder
--test.html
--test.js
--test2.js
Run Code Online (Sandbox Code Playgroud)
test.html的内容:
<html>
<head>
<script type="text/javascript" src="test.js"></script>
<script type="text/javascript" src="test2.js"></script>
</head>
</html>
Run Code Online (Sandbox Code Playgroud)
test.js的内容:
console.log('test before');
throw('foo');
console.log('test after');
Run Code Online (Sandbox Code Playgroud)
test2.js的内容:
console.log('test 2');
Run Code Online (Sandbox Code Playgroud)
打开test.html时的输出(在控制台中):
test before test.js:1
Uncaught foo test.js:2
test 2
Run Code Online (Sandbox Code Playgroud)
从这个测试中,你可以看到test2.js仍然运行,即使test.js抛出错误.但是,test.js在遇到错误后停止执行.
| 归档时间: |
|
| 查看次数: |
7940 次 |
| 最近记录: |