JavaScript是一门单线程的语言,单线程就是只有一个线程,同一时间只能做一件事。两段JS不能同时执行。

原因:这是为了避免DOM渲染的冲突:浏览器需要渲染DOM,JS也可以修改DOM结构;JS执行时,浏览器DOM渲染会暂停;两段JS也不能同时执行。

解决方案:异步

实现方式:Event-loop,即Js的事件循环机制

从网上找到一张图片如下:

JavaScript exit 线程 js线程机制_js事件循环

我们知道,当程序启动时, 一个进程被创建,同时也运行一个线程, 即为主线程,js的运行机制为单线程。js主线程是有一个执行栈的,所有的js代码都会在执行栈里运行。在执行代码过程中:

  1. 同步代码放在主进程中直接执行
  2. 异步代码先放到异步队列:如果遇到一些异步代码(比如setTimeout,setInterval,ajax,promise.then以及用户点击等操作等),那么浏览器就会将这些代码放到一个异步进程中去等待,不阻塞主线程的执行,主线程继续执行栈中剩余的代码,当异步进程处理完毕后(比如setTimeout时间到了,ajax请求得到响应),将相应的异步任务(回调函数)放到异步队列中等待执行。
  3. 待同步代码执行完步,轮询执行异步队列里的任务:当主线程执行完栈中的所有代码后,它就会检查异步队列是否有任务要执行,如果有任务要执行的话,从队列取出第一个任务队列推到主线程的执行栈中执行。如果当前任务队列为空的话,它就会一直循环查询任务队列等待任务到来。因此,叫做事件循环。
console.log(1)
setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');
//1
//one
//two

//three

note:立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。因此:上述代码中setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one');则是立即执行,因此最先输出。

这个关于Promise.resolve()的解释我取自阮一峰老师的ES6入门。还有一种解释可以参考这个文章。有更好的解释欢迎大家补充讨论。