所有的任务分为两种,一种是同步任务,一种是异步任务。 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务; (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。 setTimeOut函数为异步任务,for循环为同步任务,setTimeOut里的函数为回调函数。执行顺序为:同步优先,异步靠边,回调垫底。所以即使setTimeOut的时间参数是0依然会放到任务队列里,而不是主线程。主线程执行完for循环以后才执行异步任务setTimeOut。另外setTimeout()只是将事件插入了"任务队列",必须等到当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。要是当前代码耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。 javascript是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。于是就有一个概念——任务队列。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。于是JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准? 所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成这门语言的核心特征,将来也不会改变。 注:所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。 总结:计算机中的同步就是排队等待,假如你是第一百零一个备胎,那你只能等前面的一百个爆了之后才能‘处理'你。异步就是,尽管你是第一百零一个,她还是能照顾到你的感受。
例: 也就是说,setTimeout里的函数并没有立即执行,而是延迟了一段时间,满足一定条件后,才去执行的,这类代码,我们叫异步代码。 总结:同步可以保证顺序一致,但是容易导致阻塞;异步可以解决阻塞问题,但是会改变顺序性,根据不同的需要去写你的代码。 Promise是异步的,是指他的then()和catch()方法,Promise本身还是同步的,所以这里先执行a变量内部的Promise同步代码。(同步优先) 注意 同步(Promise)>异步(微任务(process.nextTick ,Promises.then, Promise.catch ,resove,reject,MutationObserver)>宏认为(setTimeout,setInterval,setImmediate)) process.nextTick> Promises.then 同步代码执行完成后,才会再去执行异步,哪怕异步已经到了执行的时间了。 JavaScript的任务分为微任务(Microtasks)和宏任务(task);
[宏任务:macro task] - 定时器 - 事件绑定 - ajax - 回调函数 - Node中fs可以进行异步的I/O操作 [微任务:micro task] - Promise(async/await) => Promise并不是完全的同步,当在Excutor中执行resolve或者reject的时候,此时是异步操作,会先执行then/catch等,当主栈完成后,才会再去调用resolve/reject把存放的方法执行 - process.nextTick (node中实现的api,把当前任务放到主栈最后执行,当主栈执行完,先执行nextTick,再到等待队列中找) - MutationObserver (创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。) 任务队列到达时间后先进先出的原则
参考: 1:https://blog.csdn.net/qq_40959677/article/details/95961443
![]() ![]() |
|