JS的执行机制
JS的执行机制
我觉得如果要说JS的执行机制,先来一道经典的面试题吧。这道题先放在这里一会回来解答
for(var i = 0; i < 5; i++) { setTimeout(function(){ console.log(i); },1000) }
JavaScript语言的一大特点就是单线程。也就是说同一时间只能做一件事。这是因为JavaScript这门简本语言诞生的使命所导致——JavaScript是为处理页面中用户的交互,以及操作DOM而诞生的。比如我们对某个元素进行添加和删除操作,不能同时进行。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
为了解决JS单线程的问题JS中出现了同步任务和异步任务
同步
前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。比如做饭的同步做法:我们要烧水煮饭,等水开了(10分钟之后),再去切菜,炒菜。
异步
你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。比如做饭的异步做法,我们在烧水的同时,利用这10分钟,去切菜,炒菜。
同步和异步的本质区别:这条流水线上的各个流程的执行顺序不同。比如我不再需要等待水烧开了再去炒菜了,会大大节省时间,增加效率。
JS中所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。
同步任务指的是:
在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是:
不进入主线程、而进入”任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行。

JS事件执行机制(事件循环)


由于主线程不断重复地获得任务、执行任务、在获得任务、在执行。这种执行机制称为事件循环。
再来看前面那道题
1.等执行栈内地同步地for循环执行结束出栈后,线程才会从任务队列里拉取异步地定时器地回调函数
for(var i = 0; i < 5; i++) { console.log(i); setTimeout(function(){ console.log(i); },1000) }
//先输出1234;在输出5个5
2.尽管循环中的五个函数是在各个迭代中分别定义地,但是他们都被封闭在一个共享地全局作用域中,因此实际上只有一个i
解决办法:
1.ES6 使用let声明变量。使用let声明地变量具有块级作用域,这样每次每次迭代都会在声明一次。
2.闭包。使用闭包地时候要注意添加自己地变量。因为不添加自己的变量,回调函数引用地还是那个唯一的变量i。
最后送给大家一道题目,感兴趣的可以试试。
console.log('start');
setTimeout(function () {
console.log('你猜我输出在哪');
}, 0);
console.log('end');
for (var i = 0; i < 10; i++) {
console.log(i);
}
// console.log('-----------------------');
console.log('start');
for (var i = 0; i < 3; i++) {
(function (index) {
setTimeout(function () {
console.log(index);
}, 0);
})(i);
}
console.log('end');

浙公网安备 33010602011771号