JavaScript 既是单线程又是异步的,请问这二者是否冲突,以及有什么区别?
15 个回答

而异步机制是浏览器的两个或以上常驻线程共同完成的,例如异步请求是由两个常驻线程:JS执行线程和事件触发线程共同完成的,JS的执行线程发起异步请求(这时浏览器会开一条新的HTTP请求线程来执行请求,这时JS的任务已完成,继续执行线程队列中剩下的其他任务),然后在未来的某一时刻事件触发线程监视到之前的发起的HTTP请求已完成,它就会把完成事件插入到JS执行队列的尾部等待JS处理。又例如定时触发(settimeout和setinterval)是由浏览器的定时器线程执行的定时计数,然后在定时时间把定时处理函数的执行请求插入到JS执行队列的尾端(所以用这两个函数的时候,实际的执行时间是大于或等于指定时间的,不保证能准确定时的)。
所以,所谓的JS的单线程和异步更多的应该是属于浏览器的行为,他们之间没有冲突,更不是同一种事物,没有什么区别不区别的。

Javascript 本身是单线程的,并没有异步的特性。
由于 Javascript 的运用场景是浏览器,浏览器本身是典型的 GUI 工作线程,GUI 工作线程在绝大多数系统中都实现为事件处理,避免阻塞交互,因此产生了 Javascript 异步基因。此后种种都源于此。
所有涉及到异步的方法和函数都是由浏览器的另一个线程去执行的,程序员所能控制的"另一个线程"也仅限于这些方法。
但凡这种「既是单线程又是异步」的语言有一个共同特点:它们是 event-driven 的。驱动它们的 event 来自一个异构的平台。这些语言的 top-level 不象 C 那样是 main,而是一组 event-handler。虽然所有 event-handler 都在同一个线程内执行,但是它们被调用的时机是由那个驱动平台决定的。而且设计要求每个 event-handler 要尽快结束。未做完的工作可以通知那个异构的驱动平台来完成。所以那个驱动平台可以有许多线程。
(Thread per request 这个说法是错误的,已经有答案反对。其实想想也不可能,JavaScript 根本没有语言级别的 synchronization-primitive,怎么可能支持 TPR。)
本质原因是这一类脚本引擎在实现过程中并没有对应的线程概念,以及引擎能否被多线程安全访问。
如果多个模块在多个线程中运行,并且同时征用脚本引擎来处理一些策略代码时,就产生线程安全问题。要么对虚拟机加锁,要么就是使用事件队列,让虚拟机不停的从事件队列里取事件、执行,将主动权转给虚拟机。通常后一种是比较理想的方式,也是现在的大多数脚本运行环境所提供的。
事件的发生和对事件的处理由于事件队列的存在,之间存在一个等待事件,从而产生一定的时间差——也就是异步了。因此,可以说,乏是使用事件队列来实现的脚本运行环境,通常也都是异步的。
至于你说的单线程,如果整个系统仅有一个线程运行,那将不存在多线程对虚拟机的并发访问,也不需要考虑线程安全了。就不要事件队列,当事件发生时,直接调用虚拟机接口,执行脚本函数,也就不存在异步了。
异步调用把回调加入一个队列,等待主栈空闲



AJAX异步加载是通过浏览器实现的
Javascript执行到相应语句时,向浏览器提交个请求并告诉它回调函数,然后继续执行后面的语句
服务器返回请求后,浏览器调用之前的回调函数(在Js执行完当前不宜中断的语句之后)

一、首先理解一下什么是异步:异步就是把事情交给别人(浏览器)去做,所以自己(js执行线程)不 会阻塞。别人什么时候做什么时候做完我是不关心的。
二、js在浏览器中怎么执行:js执行线程在执行某一js语句的时候会给浏览器发送请求并告知回调函数,然后js执行线程又继续执行其他语句了。等请求完成后浏览器会将回调函数放入执行队列的队尾等待执行。
三、异步是如何实现的:异步是靠浏览器的两个或者两个以上的常驻线程来完成的,第一个就是js的执行线程,第二个就是事件触发线程,js执行线程发出异步请求给浏览器,浏览器开一个新的请求线程来处理,js执行线程继续执行其他任务。那么事件触发线程呢?他就监听这个请求,如果这个请求完成了,就将该事件插入到JS执行队列的尾部等待JS处理。
四、图片能够更加直观的描述。

自己也是学习,有不正确的地方希望看到的同学能够指出来。

简单的词语概念不清才会感觉有冲突
。
异步是相对的,参照物是某个线程。
其概念是,在线程x之外做一个任务a而不阻塞线程x让线程x可以做其他的任务b.
这与 语言javascript 具有一个线程x 一点冲突也没有。任务a只要能让系统、运行时底层、远程process 做就可以了。
就算理解不了服务端后台如何做,
利用 xmlhttprequest 做异步请求的例子也应该见过嘛。


单线程的时候可以用event loop来实现异步。
多线程的话还可以用别的线程去做。

修正一下上面说每个request一个thread的说法。
以FF为例。实际上,浏览器接受到JS请求的是所谓的主线程。主线程会将此JS事件封装后,指派给专门负责JS处理的线程。处理完后,JS线程同样将请求封装以后投入主线程队列返回。

所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
阮一峰大师详解

举个栗子。
绝大部分人,都是单线程,且异步的。
类比一下。
