js执行规则

2020-04-14  本文已影响0人  青色琉璃

Q1:注册函数时会发生什么?

名字会写进event table里面

Q2:js的异步

js是一门单线程语言,全部的实现异步的方法,都是用同步去模拟的。这一点灰常重要!

Q3:事件循环Event Loop

这实际上就是js的执行机制了,也就是js实现异步的方法。

Q4:js的执行和运行

执行和运行区别很大,js在不同的环境下,如node,浏览器,Ringo等,执行方式是不同的。但是运行大多指js解析引擎,是统一的。

1,关于javascript

h5中提出了Web-Worker,但是js单线程这一点仍未改变,所谓的多线程都是用单线程模拟出来的!

2,Event Loop事件循环

js分同步任务和异步任务。

当我们打开网站时,网页的渲染过程就是一大堆同步任务,比如页面骨架和页面元素的渲染。而像加载图片音乐之类占用资源大耗时久的任务,就是异步任务。

(画图不易,且画且珍惜)


1586852433.png

如何判断主线程为空?

js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。


let data = [];

$.ajax({

    url:www.javascript.com,

    data:data,

    success:() => {

        console.log('发送成功!');

    }

})

console.log('代码执行结束');

分析:
(1) Event Table注册success函数
(2) 执行console.log('代码执行结束');
(3) ajax完成,success函数进入Event Queue
(4) 执行success函数

3,setTimeOut


function task(){

    console.log('定时器')

}

function sleep(delay) {

var start = (new Date()).getTime();

while((new Date()).getTime() - start < delay) {

    continue;

  }

}

console.log('开始')

setTimeout(() => {

    task

}, 3000)

sleep(4000);

console.log('睡眠之后')

分析:

(1)console.log('开始'),task进入Event Table

(2)执行sleep函数,主线程会卡在这儿,直到函数执行完成

(3)3秒之后,计时时间timeout结束,task进入Event Queue,但是sleep函数仍旧在执行,继续等待。

(4)4秒之后,console.log('睡眠之后');task进入主线程执行,结束。

4,setInterval

执行规则与setTimeOut类似,对于setInterval(fn,ms)来说,每隔ms时间,就会将fn推入Event Queue中,而不是每隔ms时间,就执行fn,这也意味着,如果fn的执行时间大于ms,那么就完全看不出有时间间隔了!!

5,Promise和process.nextTick(callback)

process.nextTick(callback)类似于node版的setTimeOut,在事件循环的下一次循环中调用callback。

续上回,除了广义的同步和异步任务,我们还有更精细的任务划分:

macro-task(宏任务):包括整体代码片段script,setTimeOut,setInterval

micro-task(微任务):Promise和process.nextTick

不同的任务类型会进入不同的Event Queue,比如setTimeOut,setInterval会进入相同的Event Queue。

时间循环的顺序,决定js的执行顺序。代码开始之后,从整体代码片段(宏任务)开始执行,同时将setTimeOut,setInterval中的函数置入Event Table中,随后执行微任务;下一轮开始,宏任务Event Queue开始执行,之后执行微任务。举个栗子:


setTimeout(function() {

    console.log('setTimeout');

})

new Promise(function(resolve) {

    console.log('promise');

    resolve();

}).then(function() {

    console.log('then');

})

console.log('console');

分析:

这段代码作为宏任务,进入主线程。

遇到setTimeout,将其回调函数注册后置入Event Queue。

遇到new Promise,立即执行console.log('promise')。then函数进入微任务Event Queue。

console.log('console');

第一个宏任务结束,检查微任务,执行then函数。

第一轮结束,开始第二轮。宏任务中setTimeout回调函数执行。

结束

关系图如下所示(抠图不自赏)


1586852481.png

下面,上主菜:


console.log('1');

setTimeout(function() {

    console.log('2');

    process.nextTick(function() {

        console.log('3');

    })

    new Promise(function(resolve) {

        console.log('4');

        resolve();

    }).then(function() {

        console.log('5')

    })

})

process.nextTick(function() {

    console.log('6');

})

new Promise(function(resolve) {

    console.log('7');

    resolve();

}).then(function() {

    console.log('8')

})

setTimeout(function() {

    console.log('9');

    process.nextTick(function() {

        console.log('10');

    })

    new Promise(function(resolve) {

        console.log('11');

        resolve();

    }).then(function() {

        console.log('12')

    })

})

分析:

第二轮开始

第二轮输出2,4,3,5。开始第三轮

第三轮输出9,11,10,12

三轮结束,最后输出1,7,6,8,2,4,3,5,9,11,10,12。

(请注意,node环境下的事件监听依赖libuv与前端环境不完全相同,输出顺序可能会有误差)

6,总结

微任务和宏任务还有很多种类,比如setImmediate等等,执行都是有共同点的,有兴趣的同学可以自行了解

javascript是一门单线程语言

Event Loop是javascript的执行机制

原文链接:https://juejin.im/post/59e85eebf265da430d571f89

上一篇下一篇

猜你喜欢

热点阅读