当前位置: 首页 > 面试题库 >

我知道回调函数异步运行,但是为什么呢?

柳刚豪
2023-03-14
问题内容

语法的哪一部分提供了该函数应在其他线程中运行并且是非阻塞的信息?

让我们考虑一下node.js中的简单异步I / O

 var fs = require('fs');
 var path = process.argv[2];

  fs.readFile(path, 'utf8', function(err,data) {
   var lines = data.split('\n');
   console.log(lines.length-1);
  });

是什么使它在后台发生的呢?任何人都可以准确地解释它,还是可以粘贴指向一些好的资源的链接?我到处看的地方都有很多关于什么是回调的信息,但是没有人解释为什么它实际上如此工作。

这不是关于node.js的特定问题,而是关于每种编程语言中回调的一般概念。

编辑:

我提供的示例可能在这里不是最好的。因此,我们不要考虑此node.js代码段。我通常在问-
是什么使程序在遇到回调函数时不断执行的技巧。使回调概念成为非阻塞性语法的语法是什么?

提前致谢!


问题答案:

没有 在告诉你,你的回调是异步执行的语法。回调可以是异步的,例如:

setTimeout(function(){
    console.log("this is async");
}, 100);

或者可以是同步的,例如:

an_array.forEach(function(x){
    console.log("this is sync");
});

因此,您如何知道某个函数将同步还是异步调用回调?唯一可靠的方法是阅读文档。

您还可以编写测试来确定文档是否不可用:

var t = "this is async";
some_function(function(){
    t = "this is sync";
});

console.log(t);

异步代码如何工作

Java本身不具有使函数异步的任何功能。如果要编写异步函数,则有两个选择:

  1. 使用另一个异步函数(例如setTimeout或Web Worker)来执行您的逻辑。

  2. 用C写

至于C编码函数(例如setTimeout)如何实现异步执行?这一切都与事件循环(或大部分)有关。

事件循环

Web浏览器内部有这段代码用于网络连接。最初,网络代码只能下载一件事:HTML页面本身。当Mosaic发明<img>标签时,网络代码演变为下载多种资源。然后,Netscape实施了图像的渐进式渲染,他们必须使联网代码异步,以便他们可以在加载所有图像之前绘制页面,并逐步和逐个更新每个图像。这是事件循环的起源。

在浏览器的中心,有一个从异步网络代码演变而来的事件循环。因此,它使用I /
O原语作为其核心就不足为奇了:select()或类似OS之类的类似民意调查,epoll等)。

select()C语言中的函数使您可以在单个线程中等待多个I / O操作,而无需生成其他线程。select()看起来像:

select (max, readlist, writelist, errlist, timeout)

要让它等待I / O(来自套接字或磁盘),您可以将文件描述符添加到中readlist,当任何I /
O通道上有可用数据时,它将返回。一旦返回,您就可以继续处理数据。

javascript解释器保存您的回调,然后调用该select()函数。当select()返回时,解释器找出哪个回调与哪个I /
O通道关联,然后调用它。

方便地,select()还允许您指定一个timeout值。通过仔细管理timeout传递给select()您的内容,可以导致将来某个时候调用回调。这是怎么setTimeoutsetInterval实现。解释器会保留所有超时的列表,并计算需要传递的timeout时间select()。然后,当select()返回时,除了要确定是否由于I
/ O操作需要调用任何回调外,解释器还会检查是否需要调用任何过期的超时。

因此,select()仅涉及实现异步功能所需的几乎所有功能。但是现代浏览器也有网络工作者。对于网络工作者,浏览器会生成线程以异步执行javascript代码。为了与主线程通信,工作人员必须仍然与事件循环(select()函数)交互。

在处理文件/磁盘I / O时,Node.js也产生线程。I / O操作完成后,它将与主事件循环通信回去,以使适当的回调得以执行。



 类似资料:
  • 我有一个异步函数,它调用其中的另一个异步函数。此异步函数正在返回" 你能帮我解决这个问题吗? 以下是第一个异步函数: 如你所见,我调用updateAllProducts函数,并将该值存储到一个变量调用newAllProducts. updateAllProducts是另一个异步函数。 以下是updateAllProducts的代码: 此updateAllProducts函数正在调用另一个异步函数调

  • 问题内容: 我的代码: 当我尝试运行这样的东西时: 我越来越: 但为什么? 我的主要目标是将令牌(从令牌中返回承诺)转换为变量。然后才执行一些操作。 问题答案: 只要其结果尚未解决,promise将始终记录未决。无论promise状态如何(已解决或仍处于待处理状态),您都必须调用promise来捕获结果: 这是为什么? 承诺只是向前的方向;您只能解决一次。a的解析值传递给其或方法。 根据Promi

  • 我的代码: 当我尝试运行这样的东西时: 我得到了: 但为什么? 我的主要目标是将返回承诺的中的token转换为一个变量。然后才预形成一些动作。

  • 我是Spring的新人。我学习,但在学习过程中我出错了。我为Spring使用基于XML的配置,这里是编译错误: 线程“main”org . spring framework . beans . factory . beancreationexception中出现异常:创建在类路径资源[Beans.xml]中定义的名为“helloGeorgia”的bean时出错:设置属性值时出错;嵌套异常为org

  • 然而,在我下面的代码中,我希望在这两个示例中都花费相同的15秒(每个任务5秒),如本文所述。然而,第二个示例只需要5秒,同时运行所有3个示例也需要5秒来完成第二个示例。原来的文章花了5秒,但我把它改成了1秒的延迟,让它更明显。 有没有人能解释一下这是怎么回事,为什么它看起来像线程一样运行?

  • 问题内容: 假设我有这段代码 我想知道的是该函数是否将异步执行。 问题答案: 设完成为Call(执行者,未定义,«resolvingFunctions。[[Resolve]],resolvingFunctions。[[Reject]]»)。 如果完成是突然完成,则 令status为Call(resolvevingFunctions。[[Reject]],undefined,«completion。