1.前言
javascript 是一门(动态、弱类型、面向对象)单线程,解释性(脚本)语言。执行过程是自上而下,一行一行的。ps:要明确一个观念,所谓的js、primise、$nextTick、axios、同步异步、微任务宏任务……一切的一切只不过都只是个工具而已,他的出现只为解决问题,他们的存在也是为解决问题才存在。
本篇文章尽量不涉及专业名词,尽可能用通俗易懂的词语,解释JavaScript的运行机制,及阐述同步任务和异步任务。注:异步任务又细分为微任务和宏任务。
2 生活举例
现在我就是JavaScript。我妈让我回家吃饭,吃完饭去洗漱,然后睡觉。我按部就班的吃饭、洗漱、睡觉,很简单么,按流程顺序走就完事了。
第二天,我去银行上班,我是窗口的业务员,别人来办业务,就会排队,我按照排队的人的顺序,每次给一个人办业务,有时候,有那么个人磨磨唧唧,这事那事的耽误我不少时间,后面排队的人很着急,可是没办法啊,倒霉白。可惜了,整个银行就我这一个窗口。看看隔壁的银行,窗口老多了,不用等半天,而且遇到磨磨唧唧的人也会好很多。
第三天,我想到一个好办法! 有一个办业务磨磨唧唧的人,我对她说,你先去天津教育大厦买一瓶水,然后再到我这里来。于是,我把他打发走了,虽然我最终还是要处理这个磨磨唧唧的人,可是剩下的人就可以立刻帮他们办业务了,或许等那个墨迹的人回来,我这里就很空闲,这样就不会耽搁时间了,妙啊。
3 由浅:
在深入之前,先了解一下概念:
1.单线程和多线程
单线程:我只有一只手。
多线程:我是哪吒,能同时拿手机,敲代码,吃冰柜。
2.进程和线程的概念和区别:百度。
3.并发及高并发?
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。最惨的是来了电话我不接,吃完饭才接。
无论上一个开始执行的任务是否完成,当前任务都可以开始执行并发的关键是你有处理多个任务的能力,不一定要同时
其实,与之相反的是,你只能等待上一个任务结束,才能执行下一个任务。
4.并行及高并行?
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
4.1 并行的关键是你有同时处理多个任务的能力。
4.2 最关键的点就是:是否是『同时』。
总结:js是通过队列机制,事件机制实现并发的。而所谓的同步异步也是基于js的运行机制,才产生的。
5.宏任务和微任务:他俩执行的时候不是放在一个执行队列里,先执行微任务队列,在执行宏任务。所以:同步任务 > 异步任务(微任务)>异步任务(宏任务)
4 javascript事件循环
- 同步任务
- 异步任务
同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
当指定的事情完成时,Event Table会将这个函数移入Event Queue。
主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
上述过程会不断重复,也就是常说的Event Loop(事件循环)。
总结:刚开始正常是一行一行执行代码。遇到异步任务,就把他扔到异步处理程序里面。先执行同步任务,同步执行完毕后去事件队列(eventloop)里面去执行异步程序,主线程执行完异步任务后,再去任务队列看看还有没有,有的话,再执行,再回去看有没有…一直循环,直到所有代码执行完毕。
5 举例异步之宏任务: setTimeout
他是一个经典宏任务,举例一下他的使用,来验证js的运行机制。请问这个定时器里面的函数会在3秒之后调用吗?
答案:不可能。首先定时器会被扔到任务队列中,接着执行同步任务for循环,结果掉进坑了,出不来了,3秒后,定时器说:‘哎!我到点了,该执行我里面的fn()函数了’,结果js说:‘等……等一下…呃!’ 这个定时器等了远远超过3秒,具体啥时候就不一定了。第二个,定时器如果不写延时时间的话,最早可得的空闲时间执行,而浏览器默认大概4毫秒。
setTimeout(() => { fn() },3000) for(let i = 0 ; i < 一万万亿次; i++) //随便举例,切勿当真,不然崩溃别找我。
5.1宏任务有哪些?
setTimeout
setInterval
script
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Nodejs环境)
6 异步之微任务:Promise与process.nextTick(callback)
我理解的promise是一个为了解决回调地狱而设计出的一个对象,里面有一些方法。他本身是同步的(就一对象而已),只不过里面的then是异步的,但then的目的是同步(或者更像同步,毕竟同步最容易理解),以及基于promise的async,await
微任务包含:
Promise.then Object.observe MutaionObserve process.nextTick(Node.js环境)
7.好了,试试手吧
输出 1 2 4 5 3 6 <script> const promise = new Promise((resolve,reject)=>{ console.log(1); resolve(5) 可以看成是监听then(val)做完了的状态,其实可以把它看成是同步的 console.log(2); }).then((val)=>{ console.log(val); }) console.log(4); promise.then(()=>{ console.log(3); }) setTimeout(()=>{ console.log(6); },0) </script>
8.入深
下面这个包含所有任务,且局中局套中套。我会详细解释,为什么这么输出。
console.log('1'); setTimeout(function() { console.log('2'); process.nextTick(function() { console.log('3'); }) new Promise(function(resolve) { console.log('4'); resolve(); }).then(function() { console.log('5') }) }) process.nextTick(function() { console.log('6'); }) new Promise(function(resolve) { console.log('7'); resolve(); }).then(function() { console.log('8') }) setTimeout(function() { console.log('9'); process.nextTick(function() { console.log('10'); }) new Promise(function(resolve) { console.log('11'); resolve(); }).then(function() { console.log('12') }) })
额,还有好多想法写不出来,火候不到,时间不到,等以后再来补上吧。