Cho*_*ang 6 javascript ajax multithreading asynchronous event-loop
人们普遍认为JavaScript本质上是单线程的,但可以异步运行。我想知道像这样的单线程模型如何处理非阻塞的AJAX请求?
假设在浏览器中触发了非阻塞AJAX请求,但没有立即得到响应。如果事件循环不断检查响应,执行是否不会被阻塞?当没有响应时,事件循环是否继续检查其状态并将任务“重新添加”到宏任务队列的后面?
据我了解,Node.js会静默生成线程以处理访问磁盘,数据库,网络套接字等的I / O操作。浏览器中的JavaScript是否也生成线程来处理AJAX?
可能会问类似的问题:
var img = new Image();
img.onerror=function(){alert('error: '+this.src);}
img.onload=function(){alert('image loaded: '+this.src);}
img.src='path/to/image.jpg';
Run Code Online (Sandbox Code Playgroud)
上面的代码的最后一行是否由于该语句似乎是非阻塞的而导致产生了另一个线程?
人们普遍认为JavaScript本质上是单线程的,但可以异步运行。
确实指定了JavaScript¹,使得在任何给定时间只能在一个域中执行单个线程。(领域是全局环境及其关联的对象;例如[浏览器上的窗口/选项卡。]您可以具有多个活动线程(在不同的窗口中,或通过Web worker),并且它们可以彼此通信(通过postMessage)甚至共享一些内存(SharedArrayBuffer),但他们无法同时访问同一领域。保持领域有效的单线程避免了大量的并发编程陷阱。
我想知道像这样的单线程模型如何处理非阻塞的AJAX请求?
JavaScript一次仅在JavaScript环境中只允许一个线程并不意味着主机(浏览器)是单线程的。异步ajax请求将移交给浏览器的网络处理。
JavaScript在作业队列的基础上工作(HTML5 speec称它为任务队列,但是JavaScript规范说的是“作业”,这只是名称)。JavaScript线程从队列中拾取一个作业,将该作业运行到完成,然后拾取下一个作业(如果有)。(比这要复杂一些,但这是基本思想。)当线程正在运行作业时,没有其他线程可以在同一领域中运行另一个作业。
因此,当ajax请求完成时(成功,超时等),浏览器(可能在非JavaScript线程上)会将一个作业放入JavaScript作业队列中,以调用ajax回调。JavaScript线程接收该作业并调用回调。
值得注意的是,这也正是它对发生的其他事情(例如用户单击某事)的反应。
假设在浏览器中触发了非阻塞AJAX请求,但没有立即得到响应。如果事件循环不断检查响应,执行是否不会被阻塞?
关键是线程不会连续检查返回的响应。该线程只监视作业队列。浏览器的网络处理程序处理网络请求的完成。
¹这是在ES2015中明确提出的,但在此之前的几年中,常见环境(浏览器,Node.js)就是这种情况。有一些JavaScript环境允许一个域中有多个线程(例如Rhino,在Java VM上运行JavaScript),但它们的重要性还不足以阻止ES2015添加此要求,因此允许围绕几个新功能定义精确的语义如果可能的话,要指定它本来要复杂得多,同时对线程主题保持沉默。