开头我先用不太准确但好理解的方式进行阐述,后面进行深入一点的分析。
JavaScript是一门单线程的语言,同时只能执行一个任务,怎么可能会有异步呢?既然是异步,那就意味着一边处理被异步任务之后的任务,一边处理异步地那个任务,矛盾的!经过不断地编程和浏览大佬们的文章,我现在一句话不太准确地解释下这个问题。JavaScript的确是单线程执行的语言,而异步的处理并不是JavaScript语言来处理的,而是JavaScript执行到异步操作时,马上把这个异步操作扔给了浏览器的某些模块(如Ajax模块,DOM模块,setTimeout模块等),让浏览器并发地进行处理。也就是说,JavaScript是单线程的,而浏览器内核是多线程的,并发的。当然JavaScript执行的另一个环境Node,也是多线程的并发的。
如果用硬件的知识,就更好理解了。JavaScript就是电路板上的处理器CPU,这个CPU是单线程的。同时,电路板上还有其他硬件,定时器,信号发送接收器。CPU单线程执行,只需要给各个硬件发送指令,让它们去执行就行了,所以就有了同时有异步执行的特点。但这还没完,硬件也是会向CPU发送指令的。比如信号接收器收到信号,马上报告CPU,CPU收到后立即停止正在进行的任务,来处理信号接收器发来的任务,之后再继续刚才的任务。这里就等同于硬件中的“中断”,JavaScript中的这种中断是由“回调函数”机制实现的!
接下来,我们分析JavaScript执行机制。JavaScript是单线程的,它是在浏览器(或Node)环境中运行的。浏览器运行时,会分配给JavaScript分配一个线程(主线程),而这个主线程属于浏览器的任务队列中一个队列,这个队列中的每个单位任务按顺序排列在Stack(栈)中。每处理一个单位任务,都是一次JavaScript底层回调函数的执行。除了主队列,浏览器中还有许许多多的队列有着要等待执行的任务。主队列中有了异步处理,就会以回调函数方式扔给其他队列进行处理。而当其他队列有需要马上执行的任务,会以回调函数方式插入到JavaScript主队列中,从而立即执行。例如定时器函数,时间一到,回调函数立即扔给主线程。主线程先执行这个扔过来的定时器中的回调函数,在执行栈中按顺序排列的任务。
这就是JavaScript这种单线程语言能处理异步操作的原因,必须靠浏览器(或Node)的多线程内核。
wudipmd的这篇文章有更专业的分析。可以参考这篇图文并茂的博客。
https://www.cnblogs.com/woodyblog/p/6061671.html