让我们澄清一下您所说的一些事情:
我是 JavaScript 世界的新手(两天!!),也是我之前唯一的编码
经验是在 Java 中执行语句
依次。我明白,或者至少我读过 JavaScript
是异步的,这意味着如果有一个语句需要
执行时间较长,不持有就执行下一条语句
启动第一个语句的程序。
事情不是这样的。给定的函数在设计上要么是异步的,要么是同步的。它与执行需要多长时间完全无关。您可以拥有非常快的异步函数或非常长的同步函数。决定函数是否异步的是它的设计方式。如果它使用异步 I/O 或计时器或任何其他异步基础设施,则至少该函数的某些执行是异步的。这意味着某些函数将稍后完成,而该函数调用之后的某些代码将在异步部分完成之前执行。
我遇到了回调(实际上很多!!),但我不明白它们是如何实现的
可用于确定执行顺序。我写了一段
代码只是为了了解它是如何完成的,我当然可以使用一些
帮助。
回调用于在某些异步操作完成时通知调用代码。这可以用于消耗异步操作的结果,也可以用于执行异步操作完成后想要按顺序运行的下一段代码。
在您的代码示例中,如果您想要所需的序列,则必须在setTimeout()
回调,以便在之后调用setTimeout()
调用执行,从而为您提供所需的序列。
您还必须删除callback
论证setTimeout
打回来。该回调未随该参数一起传递,因此声明它是错误的。可以通过闭包直接从父函数访问它,如下所示:
console.log("Beginning");
function Test(callback){
setTimeout(function(){
console.log("Something that is asynchronous");
// call the callback here to indicate to the calling code
// that the asynchronous operation is now complete
callback();
},5000);
console.log("After Setting Timer");
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
这将在控制台中生成一个序列:
开始
设置定时器后
异步的东西
应该排在最后
从概念上讲,Javascript 引擎运行单个线程,并且该单个线程使用事件队列。所以,在上面的函数中,这就是发生的情况。
- 首先
console.log("Beginning");
被执行。
-
Test(tstCallback)
叫做。
- 作为执行的一部分
Test()
函数,安排了一个定时器。这会在 JS 引擎内部注册一个计时器。
- 中代码的执行
Test()
继续,console.log("After Setting Timer");
被执行,然后该函数完成。
- 当前 JS 线程执行完毕,如果事件队列中没有其他内容,则 JS 引擎无事可做,而是等待下一个事件发生。
- 一段时间后(定时器设置的 5 秒),内部定时器将触发,并将定时器事件放入 JS 事件队列中。
- 由于此时没有其他 JS 执行,因此将定时器事件从事件队列中拉出并执行。这意味着调用为计时器注册的原始回调。
- 当定时器回调被调用时,它执行
console.log("Something that is asynchronous");
线路,然后调用callback()
.
- Your
tstCallback
然后调用函数并且console.log("Should come last");
被执行。
- 异步事件完成执行,JS 引擎查看事件队列中是否还有更多事件。如果是,则将下一个事件从队列中拉出并运行。
关于 Javascript 如何处理异步操作,有许多非常好的参考资料:
JavaScript 如何在后台处理 AJAX 响应? https://stackoverflow.com/questions/7575589/how-does-javascript-handle-ajax-responses-in-the-background/7575649#7575649
JavaScript 定时器如何工作 http://ejohn.org/blog/how-javascript-timers-work/
我是否需要关心异步 Javascript 的竞争条件? https://stackoverflow.com/questions/7238586/do-i-need-to-be-concerned-with-race-conditions-with-asynchronous-javascript/7238663#7238663