很高兴可以和大家分享我的博客,这是我的第一篇博客。 由于之前在看Lambda表达式提到了闭包的概念,记得之前在前端有所耳闻,所以来研究前端一些技术。今天这里先来探讨有关Js运行机制的问题。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>for</title>
</head>
<body>
<button>11</button>
<button>22</button>
<button>33</button>
</body>
<script type="text/javascript">
var btns = document.getElementsByTagName('button');
for (var i = 0; i < btns.length; i++) {
var btn = btns[i];
btn.onclick = function(){
alert(i)
}
}
</script>
</html>
这里抛出了一个小的例子,这个例子可能很多人都见过或者做过类似这样的题,运行之后我们分别点击三个button的时候弹出的数字都是3,并不是我们预期点击每个button弹出提示分别是0,1,2 的效果。我们要找到出现这样现象的原因在哪,首先我们要理解内存模型和几个概念。
Js单线程:
在浏览器的一个页面中,该页面的的Js只有一个线程(注意:Js是单线程,但浏览器内部并不是单线程,I/O、定时器、事件监听等都是浏览器的其他线程完成的),所以叫单线程。因为是单线程,所以程序的执行顺序都是从上到下依次进行的,同一时间内只能有一段代码被执行。
注意:提到一个js单线程的概念,但这里并没有说是同一个线程。也就说是一个线程但未必是同一个线程。这点理解尤为重要
任务队列和循环事件
Stack是栈存储同步任务,可以理解为不需要回调函数的操作。Heap是堆,存储对象等。Queen是任务队列存储异步任务。到这里我们不得不提出两个概念是同步和异步的概念
同步:对于一个工作任务,我们从上到下按1,2,3顺序执行,如果是同步代码,那么执行该任务的线程就一直被占用。
异步:对于一个工作任务,从上到下按1,2,3顺序执行,如果是异步代码,那么执行该任务的到1时,线程被回收到池子,其他人可以使用,当1执行完以后,从线程取出一个新的线程继续执行。这就是异步。这也就是我们上边提到的js所说的一个线程但是未必是同一个线程。
异步的出现是为了提高线程的利用率,让可用的线程更多,而不是一个线程只做一件事。讲完同步异步 我们继续说内存模型。
Queen任务队列。一旦异步任务有了响应,就会被push到任务队列。(点击事件,定时任务,服务响应等),每个异步任务都和一个回调函数关联。Js程序在Stack栈中执行同步任务(依照后进先出的顺序),随着Stack栈中任务被执行,当所有同步任务执行完,栈内存也就清空。接下来开始读取任务队列中的任务。并把与之相关联的回调函数压入Stack栈,单线程开始执行新的同步任务,执行完毕。
讲完上边的内存模型是不是我们认为之前的例子就很合理了,一个线程执行同步任务for循环到完毕,然后读取任务队列里的异步任务。然后把新的回调函数压入栈接着执行到完毕。
到这里第一篇博客就结束了,后续大部分是关于java 的总结,如果有机会可能会针对此博客再扩展讲解一下关于stack内存和Queen内存。