js部分代码执行机制
整体代码执行概况
JS引擎是按照代码块 ('代码块间相互独立,但变量和方法共享') 来进行预处理和执行的,也就是说预处理的只是执行当前的代码块的声明函数和变量,而对于还未加载的代码块,是没法进行预处理的,这也是边编译边处理的核心所在。
执行流程:
step 1. 读入第一个代码块。
step 2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到step5。
step 3. 对var变量和function定义做“预编译处理”(永远不会报错的,因为只解析正确的声明)。
step 4. 执行代码段,有错则报错(比如变量未定义)。
step 5. 如果还有下一个代码段,则读入下一个代码段,重复step2。
step6. 结束。
js函数执行
函数声明与函数表达式的区别
函数表达式:var fun = function(){}; 函数声明: function fun(){};、 两者比较大的区别在于在解释器解析代码时,会率先读取函数声明,并使其在执行任何代码之前可用(可以访问)。而函数表达式必须等到解析器执行到它所在的代码行,才会被真正的解析执行。 例: alert(sum(b)); function sum(){ return b *= b; } ** 当然,变量声明提前的机制依旧存在,若为 var sum = function(){}; 会报错,sum is not a function; 说明sum已经被定义,但没有赋值,类型为 undefined;
任务队列: 队列模块基于数据缓存模块和数组实现
常见情况: 操作DOM,事件循环,定时器。 相关操作: 闭包
主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。 执行栈中的代码(同步任务),总是在读取"任务队列"(异步任务)之前执行。 举个例子: for (var i = 0; i < lis.length; i++) { lis[i].onclick = function(){ console.log(i); } }; 运行结果:i 值一直是 lis.length-1; 因为FOR循环为执行栈中的事件,当开始执行任务队列的事件时,FOR循环已经执行完毕,i 值固定。所以i 一直为 lis.length-1; 当然,我们可以采用闭包来获取,当前的 i 值。 for (var i = 0; i < lis.length; i++) { lis[i].onclick = function(num){ return function(){ console.log(num); } }(i); } 运行结果: i 值为当前被点击的 li 相对应的 i 值。
回调函数:
所谓”回调函数”(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。例: ajax的callback。
3 同步与异步的执行概况
*
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个”任务队列”(task queue)。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
(3)一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
*