为什么回调函数允许我们在Javascript中异步执行操作?

时间:2015-10-08 00:38:01

标签: javascript asynchronous callback language-concepts

我已经读过,回调会异步制作JavaScript。但我不确定我是否理解这个解释。这就是我得到的

  

回调函数允许我们以异步方式执行操作,因为它们可以确保       回调之前的行在加载之前完全完成       下一行。

这是真的吗?谢谢

2 个答案:

答案 0 :(得分:5)

首先,它不是可以启用任何内容的回调。 node.js中的给定操作或甚至基于浏览器的javascript要么是异步的,要么不是异步的。它实际上与回调无关,尽管回调通常用于传递异步操作的结果。

例如,Javascript的array.forEach()使用回调,但它不是异步的。因此,异步操作是异步的,因为它们的底层实现是非阻塞的。通过进行函数调用来启动操作,操作在后台进行,其余代码继续运行。同时,当异步操作完成时,通常需要告诉您的代码它已完成并可能传达一些结果。回调函数是用于传递异步操作完成的所选机制。

  

我已经读过,回调会异步制作JavaScript。

不,这不是真的。回调也可以与同步操作一起使用。仅仅因为一个使用回调不会使任何异步。操作的底层本机代码实现必须是异步的(例如Ajax调用或其他网络操作)。回调用于传递异步操作的结果。它们也有许多其他非异步用途。因此,回调只是异步操作中使用的一种工具,而回调也是一种具有许多其他用途的工具。你不能说callback === asynchronous

  

回调函数允许我们异步地执行操作,因为它们   确保回调之前的行完全完成   在加载下一行之前。

很难确切地说出你的意思,但这对我来说听起来不对。使用异步操作时,代码通常不按文件中的顺序执行。例如,如果您这样做:

console.log("async start");
callSomeAsyncOperation(function(result) {
    console.log("async done");
});
console.log("I'm here now");

你会在日志中看到这个:

async start
I'm here now
async done

回调和事件队列解释

了解异步操作的工作原理也很有用。 Javascript在事件队列中运行。给定的Javascript代码序列运行完成。完成后,引擎会查看事件队列以查看是否还有其他事件要处理。如果是,则拉出队列中的第一个事件,并调用为该事件注册的回调。这将启动一个新的Javascript代码序列运行。该代码继续运行直到完成。完成后,引擎会检查另一个事件。如果有,则通过调用与该事件关联的回调来处理它。当没有更多事件要处理时,引擎进入休眠状态等待下一个事件。当一个事件发生时(在主Javascript thead之外),它会被添加到队列中,并且将它添加到队列的过程会导致JS引擎唤醒并为该事件提供服务。

编写Javascript时,通常会为事件注册和事件处理程序。这在Javascript中的工作方式是你说你感兴趣的事件(也可能包括指定一些其他信息,比如你正在寻找事件的对象),然后传递它是一个函数引用。实际上,在发生此事件时,您告诉Javascript引擎您希望它调用您的函数引用。这种类型的函数引用称为“回调”。它只是一个普通的函数,但是它被使用的上下文被称为“回调”,因为其他一些代码将在以后的某个时间通过执行你的函数“回调你”。然后,您可以在该函数引用(在该回调函数内)中放置可以响应该事件的相应代码。根据事件的类型,您可能只会被调用一次,或者每次事件发生时都会给您打电话。

您可以在这些引用中详细了解此事件队列和回调的工作原理:

Run Arbitrary Code While Waiting For Callback in Node?

blocking code in non-blocking http server

Hidden threads in Javascript/Node that never execute user code: is it possible, and if so could it lead to an arcane possibility for a race condition?

How does JavaScript handle AJAX responses in the background?(关于浏览器的文章,但概念是一样的)

答案 1 :(得分:1)

首先,让我们了解callback is(根据定义):

  

在计算机编程中,回调是一段可执行代码   作为参数传递给其他代码,预计会回调   (执行)在某个方便时间的参数。调用可能是   在同步回调中​​是立即的,或者可能在以后发生   时间与异步回调一样。在所有情况下,意图是   将函数或子例程指定为实体,具体取决于   语言,或多或少类似于变量。

现在,谈论Javascript,并不总是回调是异步的。例如:

function syncOperation(callback) {
  callback();
}

syncOperation(function() {
  console.log('a');
  console.log('b');
});

console.log('c');

该回调是同步的,因为它不进行任何异步操作。如果您打开控制台并运行上面的代码,您会看到它会记录a,然后是b,然后是c

现在,让我们看一个异步的例子:

function asyncOperation(callback) {
  setTimeout(callback, 0);
}

asyncOperation(function() {
  console.log('a');
  console.log('b');
});

console.log('c');

您首先会看到c,然后ab。那是因为setTimeout函数异步运行。

一些内置的Javascript函数是异步的,它们将运行,并且在某些时候,它们将调用您作为参数返回传递的函数。这就是为什么你这样做:

var a = 'text';
setTimeout(function() { a = 'new text'; }, 0);
console.log(a);

您将在控制台text中看到,因为它将在变量更改之前运行。