1. 背景介绍
javascript的单线程特性
因为javascript语言是一门“单线程”的语言,因此,javascript就像一条流水线,仅仅是一条流水线而已,要么加工,要么包装,不能同时进行多个任务和流程。javascript
任务队列
单线程就意味着,全部任务须要排队,前一个任务结束,才会执行后一个任务。若是前一个任务耗时很长,后一个任务就不得不一直等着。因而就有一个概念——任务队列。若是排队是由于计算量大,CPU忙不过来,倒也算了,可是不少时候CPU是闲着的,由于IO设备(输入输出设备)很慢(好比Ajax操做从网络读取数据),不得不等着结果出来,再往下执行。因而JavaScript语言的设计者意识到,这时主线程彻底能够无论IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回告终果,再回过头,把挂起的任务继续执行下去。html
事件循环
主线程从"任务队列"中读取事件,这个过程是循环不断的,因此整个的这种运行机制又称为Event Loop(事件循环)。 java
2. 知识剖析
名词解析
那么这里说的同步和异步究竟是什么呢?js官方的文档在使用这两个词的时候并不许确,包括其余文档和不少其余词汇,都只是听起来高深,但实际应用好像跟这些词没半毛钱关系。例如“路由”这个词,不知道的人从字面意义上谁又能说出“路由”是什么意思呢?却是路由器在生活中常常遇到不会感到陌生,将route使用谷歌翻译以后,其实就是路径和线路的意思,这样路由的概念也就跃然于脑海之中了,也就是说遇到陌生的概念和词汇,大可没必要惶恐不安,重要的是理解其背后的本质web
同步和异步的概念
“同步”—— 一下就让人想到“一块儿”这个词;“异步”呢,从字面来说,好像是在不一样的(异)的ways上do something,那首先想到的词多是“一边...一边...”,好比‘小明一边吃雪糕一边写做业’,这彻底没毛病,雪糕吃完了,做业也写完了,这就是异步?这种解释十分表面,停留在这个层面显然是不够的
不管如何,作事情的时候都是只有一条流水线(单线程),同步和异步的差异就在于这条流水线上各个流程的执行顺序不一样。
能够简单地理解为:能够改变程序正常执行顺序的操做就能够当作是异步操做。例如setTimeout和setInterval函数,Ajax通讯等ajax
同步和异步的区别
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务,ok,这不难理解;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。网络
异步运行机制
只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。数据结构
全部同步任务都在主线程上执行,造成一个执行栈(execution context stack)。
主线程以外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
一旦"执行栈"中的全部同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,因而结束等待状态,进入执行栈,开始执行。
主线程不断重复上面的第三步。
回调函数
所谓"回调函数"(callback),就是那些会被主线程挂起来的代码。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应,异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。例如ajax的success,complete,error也都指定了各自的回调函数,这些函数就会加入“任务队列”中,等待执行。异步
3. 常见问题
回调函数,同步,异步,单线程,任务队列,事件循环,这么多吓人的概念,彼此的关联又是如此的紧密,得想个办法把这些串起来,并进行总结梳理.async
4. 解决方案
没法回避的核心:JavaScript 代码执行机制
JavaScript是单线程,意味着任务要一个接着一个完成,可是,若是前一个任务执行时间很长,那么后面的任务就得一直阻塞着,这样用户体验十分差。
JavaScript的设计者考虑到了这一点,因此他将JavaScript的任务分为两种,在主线程上执行的任务"同步任务",被主线程挂载起来的任务"异步任务",后者通常是放在一个叫任务队列的数据结构中
一旦单线程内的全部同步任务执行完毕了,系统就会读取“任务队列,这至关于一个while循环,因此也称为事件循环
读取任务队列中的异步任务所采用的方法就是使用回调函数
5. 编码实战
6. 扩展思考
同步和异步在社会生活中的映射
在公路上,汽车一辆接一辆,有条不紊的运行。这时,有一辆车坏掉了。假如它停在原地进行修理,那么后面的车就会被堵住无法行驶,交通就乱套了。幸亏旁边有应急车道,能够把故障车辆推到应急车道修理,而正常的车流不会受到任何影响。等车修好了,再从应急车道回到正常车道便可。惟一的影响就是,应急车道用多了,原来的车辆之间的顺序会有点乱。函数
同步能够保证顺序一致,可是容易致使阻塞;异步能够解决阻塞问题,可是会改变顺序性。改变顺序性其实也没有什么大不了的,只不过让程序变得稍微难理解了一些。
回调函数(callback)
约会结束后你送你女友回家,离别时,你确定会说:“到家了给我发条信息(call me back),我很担忧你。” 对不,而后你女友回家之后还真给你发了条信息。小伙子,你有戏了。其实这就是一个回调的过程。你留了个参数函数(要求女友给你发条信息)给你女友,而后你女友回家,回家的动做是主函数。她必须先回到家之后,主函数执行完了,再执行传进去的函数,而后你就收到一条信息了。
回调,回调,就是回头调用的意思。主函数的事先干完,回头再调用传进来的那个函数。
7. 参考文献
参考一:http://www.ruanyifeng.com/blog/2014/10/event-loop.html
参考二:https://blog.csdn.net/qq_22855325/article/details/72958345
8. 更多讨论
问题一 为何选择单线程?
JavaScript的主要用途是与用户互动,以及操做DOM。这决定了它只能是单线程,不然会带来很复杂的同步问题。
问题二 单线程意味着什么?
单线程就意味着,全部任务都须要排队,前一个任务结束,才会执行后一个任务。若是前一个任务耗时很长,后一个任务就须要一直等着。这就会致使IO操做(耗时但cpu闲置)时形成性能浪费的问题。
问题三 如何解决单线程带来的性能问题?
答案是异步!主线程彻底能够无论IO操做,暂时挂起处于等待中的任务,先运行排在后面的任务。等到IO操做返回告终果,再回过头,把挂起的任务继续执行下去。因而,全部任务能够分红两种,一种是同步任务(synchronous),另外一种是异步任务(asynchronous)
原文:https://blog.csdn.net/web_zyx/article/details/81880702 \