一、关于javascript
JS是一门单线程语言,这意味着所有的任务都需要排队,前一个任务结束才会执行后一个任务如果前一个任务耗时很长,后一个任务就不得不一直等着。
这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
二、同步任务和异步任务
单线程导致的问题就是后面的任务等待前面任务完成,如果前面任务很耗时(比如读取网络数据),后面任务不得不一直等待。
为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JS 脚本实现“多个线程”(JS是单线程这一核心仍未改变。所以一切”多线程”都是用单线程模拟出来的),但是子线程完全受主线程控制。于是,JS 中出现了同步任务和异步任务。
1.同步任务
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
比如有五个顾客来到了你的饭店,同步的做法是:先给第一个顾客点菜,然后做菜,结束后再给第二个人…以此类推。
2.异步任务
异步任务:不进入主线程、而进入”任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行。
比如有五个顾客来到了你的饭店,异步的做法是:先给每一个顾客点菜,点完之后给他们一个牌子并把对应的菜单放到后厨然后让他们等待,之后后厨根据他们的菜单开始做菜。
三、微任务和宏任务
异步任务又分为微任务和宏任务。
1.微任务
包括Promise,process.nextTick
Promise(async/await) => Promise并不是完全的同步,在promise中是同步任务,执行resolve或者reject回调的时候,此时是异步操作,会先将then/catch等放到微任务队列。当主栈完成后,才会再去调用resolve/reject方法执行
process.nextTick (node中实现的api,把当前任务放到主栈最后执行,当主栈执行完,先执行nextTick,再到等待队列中找)
MutationObserver (创建并返回一个新的 MutationObserver 它会在指定的DOM发生变化时被调用。)
2.宏任务
包括整体代码script,setTimeout,setInterval
定时器
事件绑定
ajax
回调函数
Node中fs可以进行异步的I/O操作
四、执行顺序
执行顺序总结:先做同步任务,在做异步任务,异步任务又分为微任务和宏任务,先做微任务在做宏任务。
同步任务 => 异步任务( 微任务 => 宏任务 )
需要知道的是JS是单线程的,他的异步编程仅仅是根据某些机制来管控任务的执行顺序,所以并不存在同时执行两个任务这一说法。
五、示例
console.log("同步任务1"); function workFun(mac) { console.log("同步任务2"); if (mac) { console.log(mac); } return new Promise((resolve, reject) => { console.log("Promise中的同步任务"); resolve("Promise中回调的异步微任务") }) } setTimeout(() => { console.log("异步任务中的宏任务"); setTimeout(() => { console.log("定时器中的定时器(宏任务)"); }, 0) workFun("定时器传递任务").then(res => { console.log('定时器中的:', res); }) }, 0) workFun().then(res => { console.log(res); }) console.log("同步任务3") /* ** 同步任务1 同步任务2 Promise中的同步任务 同步任务3 Promise中回调的异步微任务 异步任务中的宏任务 同步任务2 定时器传递任务 Promise中的同步任务 定时器中的: Promise中回调的异步微任务 定时器中的定时器(宏任务) */
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/281137.html