• Js 运行机制 event loop


    Js - 运行机制 (Even Loop)

    Javascript 的单线程 - 引用思否的说法:

    JavaScript的一个语言特性(也是这门语言的核心)就是单线程。什么是单线程呢?简单地说就是同一时间只能做一件事,当有多个任务时,只能按照一个顺序一个完成了再执行下一个。

    那为什么JS是单线程的呢?

    • JS最初被设计用在浏览器中,作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM
    • 如果浏览器中的JS是多线程的,会带来很复杂的同步问题
    • 比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
    • 所以为了避免复杂性,JavaScript从诞生起就是单线程

    为了提高CPU的利用率,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以这个标准并没有改变JavaScript单线程的本质;

    任务队列 Task queue

    在Javascript中,所有的任务分为两类:同步任务和异步任务

    同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;

    异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

    简要说明:在这里说到了   ‘主线程’   和    ‘任务队列’ ,个人简单理解: 主线程就是 Js 执行的线程 , 任务队列是异步任务暂时存放的一个事件队列;

    在Js执行中,同步任务和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入 Event Table 并注册函数。 

    当指定的事情完成时,Event Table  会将这个函数移入 Event Queue (事件队列)。

    主线程内的任务执行完毕为空,会去 Event Queue 读取对应的函数,进入主线程执行。

    上述过程会不断重复,也就是我们常说的 Event Loop(事件循环)。

    通过上边的描述,我们来看一张图更加清晰的了解  Event Loop (事件循环) 机制

    接下来我们看一个例子:

            setTimeout(function(){
                console.log('1')
            });
     
            new Promise(function(resolve){
                console.log('2');
                resolve();
            }).then(function(){
                console.log('3')
            });
     
            console.log('4');       

    首先setTimeout 是异步进入 事件队列,然后 promise 的 then 也是异步 进入事件队列 ,

    那么按照我们上边说的Js执行机制,先走主线程的同步任务,打印2 ,然后4,紧跟着执行异步任务,也就是任务队列打印1,随后是 3 , 所以结果应该是 2,4,1,3,  事实真的是这样子嘛 ?  接着往下看 : 

    Js 中的宏任务和微任务 - 略记一下

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

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

    process.nextTick(callback)类似node.js版的"setTimeout",在事件循环的下一次循环中调用 callback 回调函数)

    我们上边的  setTimeout  放到了 event queue 事件队列里 , promise 的 then 函数 也被放到了 event queue 事件队列里,然而杯具来了,这两个 queue 并不是一个队列;

    在 Js  Event Loop 机制中

    Promise 执行器中的代码会被主线程同步调用,但是 promise 的回调函数是基于微任务的

    宏任务的优先级高于微任务

    每一个宏任务执行完毕都必须将当前的微任务队列清空

    emmmm~~

    现在我们回到上边的例子中,因为 settimeout 是宏任务,虽然先执行的它,但是他被放到了宏任务的 event queue 里面,然后代码继续往下检查看有没有微任务,检测到 Promise 的 then 函数把它放入了微任务队列。等到主线进程的所有代码执行结束后。先从微任务

    queue 里拿回调函数,然后微任务queue空了后再从宏任务的queue拿函数。

    所以正确的执行结果当然是:2,4,3,1 ;

    由此延申一下  事循环-宏任务-微任务  (Event Queue - Macro - Micro )关系图:

    最后出一个小试题,看看大家是否真的理解到了 Js 的运行机制

    试题借鉴  ssssyoki    答案及分析请前往 ssssyoki 博客。

    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')
        })
    })
  • 相关阅读:
    cd的使用
    转换器模式
    装饰模式
    策略模式
    模板方法模式
    工厂模式
    类型信息
    proto编译组件使用
    proto编译引用外部包问题
    Kafka经典三大问:数据有序丢失重复
  • 原文地址:https://www.cnblogs.com/hai-cheng/p/9271777.html
Copyright © 2020-2023  润新知