有没有在告诉你,你的回调是异步执行的语法。回调可以是异步的,例如:
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);
异步代码如何工作
Javascript 本身没有任何使函数异步的功能。如果你想写一个异步函数,你有两个选择:
使用另一个异步函数,例如setTimeout
或 web worker 来执行您的逻辑。
用C写出来。
至于 C 编码的函数(如setTimeout
)是如何实现异步执行的?这一切都与事件循环(或主要)有关。
事件循环
在 Web 浏览器中,有一段用于联网的代码。最初,网络代码只能下载一件事:HTML 页面本身。当 Mosaic 发明<img>
标签时,网络代码演变为下载多个资源。然后 Netscape 实现了图像的渐进式渲染,他们不得不使网络代码异步,以便他们可以在加载所有图像之前绘制页面,并逐步且单独地更新每个图像。这就是事件循环的起源。
在浏览器的核心有一个从异步网络代码演变而来的事件循环。因此,它使用 I/O 原语作为其核心并不奇怪:(select()
或类似的东西,例如 poll、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()
您的信息,可以在将来的某个时间调用回调。这就是实施方式setTimeout
和setInterval
实施方式。解释器保留所有超时的列表并计算它需要传递timeout
给 的内容select()
。然后当select()
返回时除了找出是否有任何由于 I/O 操作需要调用的回调之外,解释器还会检查任何需要调用的过期超时。
所以select()
单独涵盖了实现异步功能所需的几乎所有功能。但是现代浏览器也有网络工作者。对于 Web Worker,浏览器会生成线程以异步执行 javascript 代码。为了与主线程通信,worker 仍然必须与事件循环(select()
函数)交互。
Node.js 在处理文件/磁盘 I/O 时也会产生线程。当 I/O 操作完成时,它会与主事件循环进行通信以导致执行适当的回调。
希望这能回答你的问题。我一直想写这个答案,但之前很忙。如果您想了解更多关于 CI 中的非阻塞 I/O 编程,建议您阅读以下内容:http : //www.gnu.org/software/libc/manual/html_node/Waiting-for-I_002fO.html
有关更多信息,另请参阅: