我知道callback函数asynchronous运行,但为什么?

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

让我们考虑node.js中的简单asynchronousI / 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); }); 

究竟是什么使得它发生在后台? 任何人都可以解释它精确或粘贴到一些好的资源的链接? 我看到的地方有很多关于callback是什么的信息,但没有人解释为什么它实际上是这样的。

这不是关于node.js的具体问题,而是关于每种编程语言中callback的一般概念。

编辑:

可能我提供的例子在这里不是最好的。 所以我们不要考虑这个node.js代码片段。 我一般问 – 什么使程序在遇到callback函数时继续执行的技巧。 callback概念是一个非阻塞的语法是什么?

提前致谢!

语法中没有任何内容告诉你你的callback是asynchronous执行的。 callback可以是asynchronous的,比如:

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

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

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

那么,你怎么知道一个函数是同步调用还是asynchronous调用呢? 唯一可靠的方法是阅读文档。

您也可以编写一个testing来了解文档是否不可用:

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

asynchronous代码是如何工作的

Javascript,本身,没有任何function,使functionasynchronous。 如果你想写一个asynchronous函数,你有两个select:

  1. 使用另一个asynchronous函数,如setTimeout或web worker来执行你的逻辑。

  2. 用C写

至于C编码的函数(如setTimeout )如何实现asynchronous执行? 这一切都与事件循环(或主要)有关。

事件循环

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

在浏览器的核心部分,有一个从asynchronousnetworking代码发展而来的事件循环。 所以使用I / O原语作为它的核心就不足为奇了: select() (或类似poll,epoll等取决于OS的东西)。

C中的select()函数允许您在一个线程中等待多个I / O操作,而不需要产生额外的线程。 select()看起来像这样:

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

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

JavaScript解释器保存你的callback,然后调用select()函数。 当select()返回解释器数字时,哪个callback与哪个I / O通道关联,然后调用它。

方便地, select()也允许你指定一个timeout值。 通过仔细pipe理传递给select()timeout ,您可以在将来的某个时间调用callback函数。 这是setTimeoutsetInterval如何实现的。 解释器保存所有超时的列表,并计算它需要作为timeout传递给select() 。 然后,除了查找是否有任何需要由于I / O操作而被调用的callback函数之外, select()返回时,解释器还会检查是否需要调用任何过期的超时值。

所以select()本身几乎涵盖了实现asynchronous函数所需的全部function。 但现代浏览器也有networking工作者。 在networking工作者的情况下,浏览器会产生线程来asynchronous执行JavaScript代码。 为了与主线程进行通信,工作人员必须仍然与事件循环( select()函数)交互。

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


希望这回答你的问题。 我一直想写这个答案,但以前忙于这样做。 如果您想了解更多关于CI中的非阻塞I / O编程的build议,请阅读以下内容: http : //www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html

callback不一定是asynchronous的。 执行完全取决于fs.readFile如何决定处理函数参数。

在JavaScript中,你可以使用setTimeout来asynchronous执行一个函数。

讨论和资源:

node.js如何实现非阻塞I / O?

并发模型和事件循环

维基百科 :

有两种types的callback,在运行时控制数据stream的方式不同: 阻止callback (也称为同步callback或callback)和延迟callback (也称为asynchronouscallback)。

首先,如果某些东西不是asynchronous的,就意味着它是阻塞的。 所以,javascript runner在该行停止,直到该函数结束(这是一个readFileSync会做什么)。

众所周知,fs是一个IO库,所以这种事情需要花费时间(告诉硬件读取一些文件不是马上就完成的),所以很明显,任何不需要CPU的东西,它是asynchronous的,因为它需要时间,并且不需要冻结其余的代码来等待另一个硬件(当CPU空闲时)。

我希望这解决了你的疑惑。