了解过javascript的都知道其最大的特色就是单线程,也就是说同一时间只能干一件事情。那么为何不能是多线程呢?缘由很简单,多线程太复杂了,假设javascript有2个线程,一个去添加dom,一个去删除dom,那么浏览器就懵逼了,这到底要我选择哪一个?因此为了不没必要要的麻烦,javascript一开始就选择了单线程。可是单线程也有问题,假设有个任务是要向服务器去请求一个文件,若是这个文件很大,那么就不能当即执行下一语句(要等到文件回来),这样就形成了浏览器假死的现象。因此html5提出了web worker标准,容许javascript建立子线程,可是规定很严格,子线程要受到主线程控制,而且不能操做dom,这种折中方法使得javascript更加灵活了。javascript
到目前为止javascript能够有子线程了,这时候再遇到像以前提到的若是一个io操做很费时间,那么就能够把这个任务挂起来,等返回结果了再来执行这个任务。因而全部的任务都变成了2种,一种是同步任务(从上到下一步一步执行),另一种就是异步任务(等有结果了再执行,即所谓的消息队列)。这2种任务进入到线程也不同,同步的从上到下依次直接进入主线程造成执行栈,异步的等有返回结果了,好比ajax请求成功了,就把成功的回调放到子线程里面去(失败就把失败的回调放到子线程里面去)。如今浏览器开始执行主线程里面的执行栈了,等主线程里面的执行栈都执行完毕了,主线程就会到子线程里面去看以前挂起到任务哪些有回调了,若是有回调了,那就把该回调内容放到主线程里面去执行,等执行完毕了再去子线程看有没有新的回调了(这里要注意的是主线程所有执行完毕,才会去子线程去看),主线程不断的重复这个步骤,这就是所谓的Event loop,也就是javascript的运行机制。比较特殊的是setTimeout,setinterval这2个方法,它们也会被放倒子线程里面去,好比我使用setTimeout(fn,3000),有时候不必定是3s以后会执行fn这个事件,还要看主线程里面的任务是否完成。html
案例1:html5
function f() { console.log("foo"); setTimeout(g, 0); console.log("baz"); h(); } function g() { console.log("bar"); } function h() { console.log("blix"); } f(); 输出的结果为:foo 、baz 、 blix 、bar
案例2 :java
var req = new XMLHttpRequest(); req.open('GET', url); req.onload = function (){}; req.onerror = function (){}; req.send(); var req = new XMLHttpRequest(); req.open('GET', url); req.send(); req.onload = function (){}; req.onerror = function (){};
这2个的执行结果都是同样的,都会先执行onload事件,由于javascript要等主线程空了才会去查看子线程有没有回调内容。web
注意点:ajax
异步的任务执行的顺序是不固定的,主要看返回的速度,假设a任务写在b任务以前,可是a任务比较大,耗时比较长,而b任务耗时短,那么b任务有了回调先会进入到子线程里面,这样会被主线程先轮询到,可是也有可能b任务网络很差,a任务先返回了,那么a任务的回调先被注册到子线程了,致使a先执行了。浏览器