你们可能都知道,JS语言的执行环境是单线程的。node
所谓单线程就是指一次只能完成一件任务,若是有多个任务,就必须排队,等前面一个任务执行完成,再执行后面一个任务,依次进行。ajax
好处:实现起来比较简单,执行环境相对单纯。浏览器
缺点:只要存在一个任务耗时好久,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死)每每就是由于某一段JS代码长时间运行(好比死循环),致使整个页面卡在某个任务,其它任务没法执行。多线程
那么为了解决这个问题。JS将任务的执行模式分为两种:同步(synchronous) 和 异步(asynchronous)。异步
同步上面已经介绍过,即后一个任务等前一个任务结束后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的。async
异步模式则彻底不一样,每个任务有一个多多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,因此程序的执行顺序与任务的排列顺序不是一致的。函数
异步模式很是重要。在浏览器端,耗时很长的操做都应该是异步执行,避免浏览器失去响应,最好的列子就是ajax操做。oop
异步调用不会阻止代码的顺序执行,而是在未来的某一个时刻触发设置好的逻辑,因此咱们:spa
1.并不知道逻辑何时会被调用;线程
2.只能定义当触发的时候逻辑是什么;
3.只能等待,同时能够去处理其余的逻辑;
setTimeout就是这样的一个异步调用。
var a = 1; function f1(a){ console.log("I am in f1"); setTimeout(function(){a+=2;console.log("f1:" + a);},1000)} f1(a); console.log("out:" + a);
获得的结果以下图所示:
I am in f1
out:1
f1:3
结果代表代码执行过程当中确实是先执行了f1函数,在执行console.log输出后,setTimeout的回调函数在执行过程当中被挂起,知道1s后才被调用,在等待执行setTImeout回调函数的时间里,JS选择执行后面的任务,即执行了console.log("out:" + a);
实际上,异步函数,如setTimeout和setInterval,是被压入了称之为Event Loop的队列。
Event Loop是一个回调函数队列。当异步函数执行时,回调函数会被压入这个队列。JavaScript引擎直到异步函数执行完成后,才会开始处理事件循环。这意味着JavaScript代码不是多线程的,即便表现的行为类似。事件循环是一个先进先出(FIFO)队列,这说明回调是按照它们被加入队列的顺序执行的。JavaScript被 node选作为开发语言,就是由于写这样的代码多么简单啊。