我已阅读Why do I have to use await for a method to run asynchronously. What if I don't want to wait for the method to finish before continuing?和Are callbacks always asynchronous?,我仍在尝试了解回调实际上是异步的。
例如,doThat
需要等待GET
数据才能执行任何操作。并且正如上面的第二个链接所述,javascript是单线程的。
doThis(doThat);
function doThis(callback) {
$.get('http://some_api/some_resource', function (data) {
callback(data);
});
};
function doThat(data) {
// Do something with data
};
我见过的唯一真正的异步功能是承诺和多个承诺,例如,我可以在动画结束时加载其他数据。当传统的回调实际上是异步的时候,我想帮助更好地理解。具体的例子有帮助。
答案 0 :(得分:4)
从定义开始:
异步,在计算机编程中,指的是独立于主程序流的事件的发生以及处理这些事件的方法。这些可能是"外面"事件,例如信号的到达,或程序发起的与程序执行同时发生的动作,而不会阻止程序等待结果。
- 戴维斯,亚历克斯(2012年)。 C#5.0中的异步,通过维基百科Asynchrony (computer programming)
在JavaScript的情况下,它的工作方式如下(简化):有一个任务队列等待主(也是唯一)线程执行。加载脚本时,它是放在此队列上的任务。任务一直运行直到它退出,没有其他任务可以中断它。但是,任务可以导致其他任务放在队列中。当一个任务完成时,队列上的下一个任务开始。如果队列为空,则之后进入队列的第一个任务立即执行。
任务进入队列的主要方式,除了作为被解析和执行的脚本的主要任务之外:触发事件会将为该事件注册的处理程序放在任务队列中,并达到由{{1}计划的时间或setTimeout
将关联的任务放在任务队列上。
在JavaScript上下文中,在相同任务("主程序流")中执行的所有内容都被称为同步。在 future 任务中执行的所有操作都称为异步。另一种说法是 - 如果下一个语句在回调之前执行,则它是异步的;如果下一个语句在回调后执行,则它是同步的。
setInterval
是一个异步调用,因为执行函数$.get(opts, callback)
的任务将在callback
事件触发时放在任务队列中。如果你有一个声明,它将首先被执行;只有在该任务完成后,由于对AJAX调用的更新而进入任务队列的任务才有可能运行。
相反,onreadystatechange
是同步调用,因为$.each(collection, callback)
将直接从callback
函数调用,而不退出当前任务,并且不会生成任何其他任务(不无论如何,each
当然可以产生额外的任务)。下一个语句必须等到callback
完成迭代each
的每个元素。
请注意,promises只是这个机制的包装器。你可以用promises做的一切,你可以没有它们,只是代码不会那么漂亮和清晰。
答案 1 :(得分:1)
例如,我可以在动画结束时加载其他数据。
这正是您可以使用代码执行的操作。请注意,在等待doThat
执行时,您可以运行其他代码(实际上“运行其他代码”会让人感到困惑)。完全像你的动画示例:
function doThis(callback) {
$.get('http://some_api/some_resource', function (data) {
callback(data);
});
};
function doThat(function (data) {
// Do something with data
});
function doAnotherThing(function (data) {
// Do something with data
});
doThis(doThat);
// without waiting for doThat to run, you can IMMEDIATELY call:
doThis(doAnotherThing);
// without waiting for either doThat or doAnotherThing you
// can output some pretty animations:
setInterval(do_animation,100);
// and without waiting for any of the above you can do anything else:
document.body.innerHTML += 'hello';
请注意,让大多数人感到困惑的是document.body.innerHTML='hello'
部分运行之前上面的任何代码。这意味着回调是异步的,因为它们在数据到达时执行 ,而不是在调用函数时执行。
请注意,并非所有回调都是异步的。例如,Array.prototype.forEach()
是同步的:
document.body.innerHTML += 'before<br>';
['hello','world'].forEach(function(x){
document.body.innerHTML += x;
})
document.body.innerHTML += '<br>after';
什么决定回调是异步还是同步的天气是调用它的函数。另见:I know that callback function runs asynchronously, but why?