天天不能不写业务,但也不能只写业务。因此选择了一个本身还在学校期间没有学明白的内容进行了巩固,同步异步问题。学习一个知识以前必先给本身一个问题三连。为何要有这个? 这个怎么用? 这个怎么回事?前端
首先JS是一个单线程的语言。单线程的含义相似于从头走到尾,谁也别管谁,前面堵车我就停(官方:单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。),没办法开多个线程。java
疑问来了?为何JS不设计成多线程的能够开多个线程同时操做。JS是能够去操做DOM的。假设JS设计成一个多线程语言。你的主线程在给DOM的innerHtml作一个赋值操做,你的另外一个线程把这个DOM结构删除了。。。。这确定不能够。(多线程能够互不干预的操做一段内存空间)。因此干脆设计成一个单线程,哪怕后期HTML5出现的web worker也是不容许操做DOM结构的,能够完成一些分布式的计算。对于dom结构咱们必须顺序操纵,坚定不容许出现对同一个dom同时进行操做。node
可是浏览器加载一些须要网络请求的好比图片资源、ajax。或者轮训的内容。因为是单线程,须要等待这些内容访问完才能够执行下面的代码。那么你发个ajax请求或者请求个图片资源,那么这段时间就什么也作不了,这种效果对程序是一种阻塞,在等待时间明明能够作些别的事情却选择了无心义的等待。(同步阻塞)这个时候异步就出现了,在涉及须要等待的操做,咱们选择让程序继续运行,在等待时间结束的时候,通知一下咱们的程序内容执行完毕,你能够操做这些资源了,这段等待时间并不影响你程序的继续执行,只是在将来的某个时间段(不肯定),有一个操做必定会执行,这就是异步。(异步非阻塞),这就是为何要有同步异步。web
(第一次了解这个的,请先补习一下定时器与promise的知识)ajax
xxxxxxxxx(一堆不肯定的代码)
setTimeout(()=>{console.log(111)},500);
复制代码
请问打印出111会在何时? 答案是500ms的时候打印算法
错!答案是500ms或者500ms之后的某个时间段。promise
首先碰见定时器后,会将定时器内的函数进行注册,也就是放入Event Table 。而后在500ms后将Event Table内注册的函数放入 Event queue。若主线程(我也就一个线程)中的call stack(调用堆栈,也就是线程中函数的一个调用栈)为空就将Event queue按顺序的放入call stack中进行执行。若是call stack并不为空, Event queue内的事件并不会进入call stack中,也就不会执行。浏览器
怎么忽然来了这么多乱七八糟,画风和刚才不同呀。难度上来了。网络
首先对于异步事件,咱们在执行到这行代码的时候会进行一个注册,将你要在将来某个时间段要执行的函数注册一下,放在Event table中。这个Event table中能够有不少事件,好比你一次发了好多ajax请求,那么他们就所有注册了。在将来的时间到了,就会把注册的事件放入Event queue(任务队列)这个任务队列就是立刻要执行的内容。多线程
任务队列何时能够执行?在主线程的call stack为空的时候,会把任务队列的第一个事件放入call stack中执行,这里面涉及一个queue(队列)的特色就是先进先出。在注册后先放入Event queue的事件就会更早的离开Event queue进入主线程执行。这个时候是否是以为本身明白点了? 唉别高兴的太早了。
setTimeout(()=>{console.log(111)},0)
let promise = new Promise((resolve,reject)=>{
console.log(222);
resolve(3333)
});
let promise2 = new Promise((resolve,reject)=>{
console.log(555);
resolve(6666)
});
setTimeout(()=>{
console.log(4444);
},0)
promise.then(res=>{
console.log(res);
});
promise2.then(res=>{
console.log(res);
});
复制代码
你说这会打印出个什么? 按理论先进先出,222 555 111 4444 333 666 你看对不对。 事实证实:222 555 333 666 111 4444 这是为何? 首先注册的事件也有不一样形态,宏任务与微任务。
常见的宏任务:setTimeout、setInterval(定时器类)
常见的微任务:promise process.nextTick(一个node环境的方法)。
这两个任务的执行规则是什么?首先在call stack中的内容执行完毕清空后,会在Event queue检查一下哪些是宏任务哪些是微任务,而后执行全部的微任务,而后执行一个宏任务,以后再次执行全部的微任务。也就是说在主线程任务执行完毕后会把任务队列中的微任务所有执行,而后再执行一个宏任务,这个宏任务执行完再次检查队列内部的微任务,有就所有执行没有就再执行一个宏任务。
在这个概念理解清楚以后,我大约明白一些了,但是我就是一行真正的脱离了定时器、事件、ajax的异步的代码也写不出来,我一直在想如何实现消息通知异步的消息通知?观察者模式吗?那也没办法模拟出来,10分钟以后我要作一个任务。想了好久。 在有一天需求评审中,咱们要作一个定时提醒的需求,这个时候后台的任务分配中选择了几天来制做定时任务。这个时候我理解了。java的定时提醒是要开一个新的线程去不断轮巡时间,能够设置的间隔可是间隔越小,越消耗机器的性能。后来查阅资料了解,JS是单线程,可是浏览器不是,只是执行JS代码的引擎是个单线程的因此JS的代码没办法开启多个线程,可是浏览器还有定时器线程、事件触发线程、异步http请求线程、GUI线程。
因此在执行定时器、事件、ajax这些异步事件的时候是另外三个线程在执行代码,并非JS引擎在作事情,在这些线程达到某一特定事件把任务放入JS引擎的线程中,同时GUI线程(渲染界面HTMl的线程)与JS线程是互斥的,在JS引擎执行时GUI线程会被冻结、挂起。
最后最后 JS是单线程可是浏览器是多线程。你的异步任务是浏览器开启对应的线程来执行的,最后放入JS引擎中进行执行。
今天基本理解了JS的异步任务是什么意思。下一节(多是下周或者大下周) 我就要针对于Promise 与async/await 以及回调地狱来进行梳理与学习了。下次仍是这个主题咱们不见不散。
公众号主要面向的是初级/应届生。内容包含咱们从应届生转换为职场开发所踩过的坑,以及咱们每周的学习计划和学习总结。 内容会涉及计算机网络、算法等基础;也会涉及前端,后台,Android等内容~