涉及异步调用时如何设置具体的执行顺序?
How do I set a specific order of execution when asynchronous calls are involved?
我是 JavaScript 世界的新手(2 天!!),我之前唯一的编码经验是在 Java 中按顺序执行语句。
我明白或者至少我读过 JavaScript 是异步的,这意味着如果有一条语句需要很长时间才能执行,那么下一条语句将在不暂停第一个语句的程序的情况下执行。
我遇到过回调(实际上很多!!),但我看不出如何使用它们来确定执行顺序。我写了一段代码只是为了了解它是如何完成的,我肯定需要一些帮助。
console.log("Beginning");
function Test(callback){
setTimeout(function(callback){
console.log("Something that takes a lot of time");
},5000);
callback();
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
我想要的是输出显示 -
Beginning
Something that takes a lot of time
Should come last
但我得到的输出是 -
Beginning
Should come last
Something that takes a lot of time
我能做些什么来按照我想要的方式获得输出吗?
将回调放在 setTimeout
内部而不是外部,因为 callback
将在 setTimeout 执行之前首先执行,因为 javascript 不会等待 setTimeout
执行( as JS is synchronous by nature) 并执行下一行,因此您不会获得所需的输出。
console.log("Beginning");
function Test(callback){
setTimeout(function(){
console.log("Something that takes a lot of time");
callback();
},5000);
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
你说的很多都是错的。 Java脚本与Java一样是顺序的,但异步调用的频率更高。如果你想让你的回调在长的东西之后被调用,你必须在长的运行程序之后调用它。像这样 -
console.log("Beginning");
function Test(callback){
setTimeout(function(callback){
console.log("Something that takes a lot of time");
callback();
},5000);
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
我已如下修改您的代码以获得所需的输出。
console.log("Beginning");
function Test(callback){
console.log("Something that takes a lot of time");
setTimeout(callback,5000);
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
setTimeout 接受一个回调函数,将在指定的时间间隔后执行
setTimeout的使用是异步部分。上面代码执行时,首先打印"Begining"控制台语句,然后调用Test函数,传入一个需要在500ms后异步执行的函数。
让我们澄清一下您所说的内容:
I am new(2 days!!) to the world of JavaScript and my only prior coding
experience is in Java where execution of statements takes place
sequentially. I understand that or at least I've read that JavaScript
is asynchronous which means that if there is a statement that takes a
long time to execute, the next statement is executed without holding
up the program for the first statement.
这不是它的工作原理。给定的函数在设计上要么是异步的,要么是同步的。它与执行所需的时间完全无关。您可以有一个非常快的异步函数或一个非常长的同步函数。决定函数是否异步的是它是如何设计的。如果它使用异步 I/O 或定时器或任何其他异步基础设施,那么至少部分函数的执行是异步的。这意味着一些函数将在稍后完成,而在此函数调用之后的一些代码将在异步部分完成之前执行。
I came across callbacks(a lot actually!!) but I couldn't see how they
could be used to determine the order of execution. I wrote a piece of
code just to understand how it could be done and I sure could use some
help.
回调用于在某些异步操作完成时通知调用代码。这可用于消耗异步操作的结果,也可用于在异步操作完成后按顺序执行下一段想要 运行 的代码。
在您的代码示例中,如果您想要所需的序列,则必须在 setTimeout()
回调中调用回调,以便在调用的 setTimeout()
执行后调用它,从而为您提供所需的顺序。
您还必须删除 setTimeout
回调的 callback
参数。该回调没有通过该参数传递,因此声明它是错误的。它可以通过闭包直接从父函数访问,如下所示:
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);
这将在控制台中生成一个序列:
Beginning
After Setting Timer
Something that is asynchronous
Should come last
从概念上讲,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()
.
- 然后调用您的
tstCallback
函数并执行 console.log("Should come last");
。
- 异步事件完成执行,JS 引擎查看事件队列中是否还有更多事件。如果是,则下一个事件从队列中拉出,它是 运行.
有很多关于 Javascript 如何处理异步操作的非常好的参考资料:
How does JavaScript handle AJAX responses in the background?
Do I need to be concerned with race conditions with asynchronous Javascript?
我是 JavaScript 世界的新手(2 天!!),我之前唯一的编码经验是在 Java 中按顺序执行语句。 我明白或者至少我读过 JavaScript 是异步的,这意味着如果有一条语句需要很长时间才能执行,那么下一条语句将在不暂停第一个语句的程序的情况下执行。 我遇到过回调(实际上很多!!),但我看不出如何使用它们来确定执行顺序。我写了一段代码只是为了了解它是如何完成的,我肯定需要一些帮助。
console.log("Beginning");
function Test(callback){
setTimeout(function(callback){
console.log("Something that takes a lot of time");
},5000);
callback();
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
我想要的是输出显示 -
Beginning
Something that takes a lot of time
Should come last
但我得到的输出是 -
Beginning
Should come last
Something that takes a lot of time
我能做些什么来按照我想要的方式获得输出吗?
将回调放在 setTimeout
内部而不是外部,因为 callback
将在 setTimeout 执行之前首先执行,因为 javascript 不会等待 setTimeout
执行( as JS is synchronous by nature) 并执行下一行,因此您不会获得所需的输出。
console.log("Beginning");
function Test(callback){
setTimeout(function(){
console.log("Something that takes a lot of time");
callback();
},5000);
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
你说的很多都是错的。 Java脚本与Java一样是顺序的,但异步调用的频率更高。如果你想让你的回调在长的东西之后被调用,你必须在长的运行程序之后调用它。像这样 -
console.log("Beginning");
function Test(callback){
setTimeout(function(callback){
console.log("Something that takes a lot of time");
callback();
},5000);
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
我已如下修改您的代码以获得所需的输出。
console.log("Beginning");
function Test(callback){
console.log("Something that takes a lot of time");
setTimeout(callback,5000);
}
function tstCallBack(){
console.log("Should come last");
}
Test(tstCallBack);
setTimeout 接受一个回调函数,将在指定的时间间隔后执行
setTimeout的使用是异步部分。上面代码执行时,首先打印"Begining"控制台语句,然后调用Test函数,传入一个需要在500ms后异步执行的函数。
让我们澄清一下您所说的内容:
I am new(2 days!!) to the world of JavaScript and my only prior coding experience is in Java where execution of statements takes place sequentially. I understand that or at least I've read that JavaScript is asynchronous which means that if there is a statement that takes a long time to execute, the next statement is executed without holding up the program for the first statement.
这不是它的工作原理。给定的函数在设计上要么是异步的,要么是同步的。它与执行所需的时间完全无关。您可以有一个非常快的异步函数或一个非常长的同步函数。决定函数是否异步的是它是如何设计的。如果它使用异步 I/O 或定时器或任何其他异步基础设施,那么至少部分函数的执行是异步的。这意味着一些函数将在稍后完成,而在此函数调用之后的一些代码将在异步部分完成之前执行。
I came across callbacks(a lot actually!!) but I couldn't see how they could be used to determine the order of execution. I wrote a piece of code just to understand how it could be done and I sure could use some help.
回调用于在某些异步操作完成时通知调用代码。这可用于消耗异步操作的结果,也可用于在异步操作完成后按顺序执行下一段想要 运行 的代码。
在您的代码示例中,如果您想要所需的序列,则必须在 setTimeout()
回调中调用回调,以便在调用的 setTimeout()
执行后调用它,从而为您提供所需的顺序。
您还必须删除 setTimeout
回调的 callback
参数。该回调没有通过该参数传递,因此声明它是错误的。它可以通过闭包直接从父函数访问,如下所示:
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);
这将在控制台中生成一个序列:
Beginning
After Setting Timer
Something that is asynchronous
Should come last
从概念上讲,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()
. - 然后调用您的
tstCallback
函数并执行console.log("Should come last");
。 - 异步事件完成执行,JS 引擎查看事件队列中是否还有更多事件。如果是,则下一个事件从队列中拉出,它是 运行.
有很多关于 Javascript 如何处理异步操作的非常好的参考资料:
How does JavaScript handle AJAX responses in the background?
Do I need to be concerned with race conditions with asynchronous Javascript?