简体   繁体   English

如果需要等待,为什么回调被认为是异步的

[英]Why are callbacks considered asynchronous if we need to wait

I've read Why do I have to use await for a method to run asynchronously. 我已经阅读了为什么我必须使用await来异步运行方法。 What if I don't want to wait for the method to finish before continuing? 如果我不想等到方法完成再继续怎么办? and Are callbacks always asynchronous? 回调总是异步的吗? and am still trying to understand when a callback is actually asynchronous. 并且仍在尝试了解回调实际上是异步的。

For example, doThat will need to wait for GET data before doing anything with it. 例如, doThat将需要等待GET数据之后才能对其进行任何处理。 And as the second link above states, javascript is single threaded. 如上面的第二个链接所述,javascript是单线程的。

doThis(doThat);

function doThis(callback) {
    $.get('http://some_api/some_resource', function (data) {
        callback(data);
    });
};

function doThat(data) {
    // Do something with data
};

The only truly async functionality I've seen is with promises and multiple promises where I can, for example, load other data while animations are wrapping up. 我所见过的唯一真正异步功能是带有promise和多个promise,例如,我可以在动画包装时加载其他数据。 I'd like help better understanding when traditional callbacks are actually asynchronous. 我想帮助您更好地了解传统回调实际上是异步的。 Concrete examples help. 具体的例子有帮助。

Starting with the definition: 从定义开始:

Asynchrony, in computer programming, refers to the occurrence of events independently of the main program flow and ways to deal with such events. 在计算机编程中,异步是指事件的发生与主程序流以及处理此类事件的方式无关。 These may be "outside" events such as the arrival of signals, or actions instigated by a program that take place concurrently with program execution, without the program blocking to wait for results. 这些可能是“外部”事件,例如信号的到来,或与程序执行同时发生的由程序引发的动作,而程序不会阻塞等待结果。

-- Davies, Alex (2012). -戴维斯(Alex)(2012)。 Async in C# 5.0, via Wikipedia on Asynchrony (computer programming) 在C#5.0中通过Wikipedia在异步上进行异步(计算机编程)

In case of JavaScript, it works like this (simplified): There is a queue of tasks waiting to be executed by the main (and only) thread. 在JavaScript的情况下,它的工作方式是这样(简化)的:存在等待主线程(和唯一线程)执行的任务队列。 When you load a script, it is a task placed on this queue. 加载脚本时,它是放置在此队列上的任务。 A task runs until it exits, and no other task can interrupt it. 一个任务一直运行到退出,其他任何任务都无法中断它。 However, a task can cause other tasks to be placed on the queue. 但是,一个任务可能导致其他任务被放置在队列中。 When one task finishes, the next task on the queue starts. 当一个任务完成时,队列中的下一个任务开始。 If the queue is empty, the first task that enters the queue afterwards gets immediately executed. 如果队列为空,则随后执行的第一个进入队列的任务将立即执行。

The main ways for tasks to enter the queue, besides being the main task of script being parsed and executed: triggering an event will place handlers registered for that event on the task queue, and reaching a time scheduled by setTimeout or setInterval will place the associated task on the task queue. 任务进入队列的主要方法,除了被解析和执行的脚本的主要任务之外:触发事件将为该事件注册的处理程序放置在任务队列中,达到setTimeoutsetInterval安排的时间将放置关联任务队列上的任务。

In JavaScript context, everything that executes within the same task ("main program flow") is said to be synchronous . 在JavaScript上下文中,在同一任务(“主程序流”)中执行的所有操作都称为“ 同步” Everything that is executed in a future task is called asynchronous . 将来的任务中执行的所有操作都称为异步 Another way to tell is - if the next statement executes before the callback, it is asynchronous; 另一种判断方法是-如果next语句在回调之前执行,则它是异步的; if the next statement executes after the callback, it is synchronous. 如果下一条语句在回调之后执行,则它是同步的。

$.get(opts, callback) is an asynchronous call, because the task that executes the function callback will be placed on the task queue when triggered by the onreadystatechange event. $.get(opts, callback)是一个异步调用,因为由onreadystatechange事件触发时,执行函数callback的任务将放置在任务队列中。 If you have a statement following it, it will get executed first; 如果后面有一条语句,它将首先被执行; it is only after that task finishes, that the task which entered the task queue because of an update to your AJAX call will have a chance to run. 只有在该任务完成后,由于AJAX调用的更新而进入任务队列的任务才有机会运行。

In contrast, $.each(collection, callback) is a synchronous call, because callback will be directly called from the each function, without exiting the current task, and will not generate any additional tasks (not by itself anyway, callback of course can generate additional tasks). 相反, $.each(collection, callback)是一个同步调用,因为callback将从each函数直接调用,而不会退出当前任务,并且不会生成任何其他任务(无论如何不是本身, callback当然可以生成其他任务)。 The next statement will have to wait until each finishes iterating over every element of collection . 下一条语句必须等待,直到each完成对collection每个元素的迭代为止。

Note that promises are simply wrappers over this mechanism. 注意,promise只是对该机制的包装。 Everything you can do with promises, you can do without them, just the code will not be as pretty and legible. 您可以用诺言做的一切,如果没有诺言,您也可以做,只是代码不会那么漂亮和清晰。

I can, for example, load other data while animations are wrapping up. 例如,我可以在动画结束时加载其他数据。

This is exactly what you can do with your code. 这正是您可以使用代码执行的操作。 Note that you can run other code (and indeed the "running other code" is what confuses people) while waiting for doThat to execute. 请注意,在等待doThat执行时,您可以运行其他代码(实际上,“运行其他代码” doThat人们感到困惑)。 Exactly like your animation example: 就像您的动画示例一样:

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';

Note that what confuses most people is that the document.body.innerHTML='hello' part runs BEFORE any of the code above it. 请注意,令大多数人感到困惑的是document.body.innerHTML='hello'部分其上方的任何代码之前运行。 Which means that the callbacks are asynchronous because they get executed when data arrives , not when the function is called. 这意味着回调是异步的,因为它们在数据到达时执行,而不是在调用函数时执行。

Note that not all callbacks are asynchronous. 请注意,并非所有回调都是异步的。 For example, Array.prototype.forEach() is synchronous: 例如, Array.prototype.forEach()是同步的:

document.body.innerHTML += 'before<br>';
['hello','world'].forEach(function(x){
    document.body.innerHTML += x;
})
document.body.innerHTML += '<br>after';

What determines weather a callback is asynchronous or synchronous is the function that calls it. 决定回调是异步还是同步的是调用它的函数。 See also: I know that callback function runs asynchronously, but why? 另请参阅: 我知道回调函数异步运行,但是为什么呢?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM