美文网首页
JavaScript 运行机制 Event loop

JavaScript 运行机制 Event loop

作者: 斯文的烟鬼去shi吧 | 来源:发表于2017-11-27 15:23 被阅读0次

    JavaScript Event Loop

    今天要分享的是javascript事件的运行机制,我们知道js是单线程的,但是为什么会是单线程?它又是怎么样运行的?

    带梯子的直接传送help i'm stuck in an event-loop
    这小哥讲得透彻 😂😂😂
    想直接看结果可以翻到底部

    历史原因

    很早以前网上冲浪越来越流行时,对于开发客户端脚本的需求也逐渐增大。这时网页已经不断地变得更大和更复杂。而更加加剧用户痛苦的是,仅仅为了简单的表单有效性验证,就要与服务器进行多次地往返交互。设想一下,用户填完一个表单,点击提交按钮,等待了 30 秒的处理后,看到的却是一条告诉你忘记填写一个必要的字段。
    急需开发一种客户端脚本语言来解决简单的处理问题。在客户端处理一部分事情,优化体验,同时也减轻了服务端的压力,当初的考虑只是一个脚本类型的辅助操作浏览器语言。
    但是JavaScript是单线程呢?
    不妨反过来想,如果js是多线程会怎么样?多个线程对同一个dom操作,这该怎么办?频繁的操作又该怎么办?浏览器的处理性能问题。所以JavaScript开发出来的原因就决定了是什么。


    事件调用机制 call stack

    接下来就是我们的重头戏js调用机制了,由于是单线程语言,这就意味着它只有一个单一的调用堆栈,也就是每次只能做一件事。
    就拿比较流行的V8引擎来说,组成由:

    • 内存堆(memory heap): 分配内存的地方(可执行代码)
    • 调用栈(call stack): 程序运行时候函数的调用过程
      v8.png

    JS运行的时候,会有栈内存(stack)和堆内存(heap),当我们用new实例化一个类的时候,这个new出来的对象就保存在heap里面,而这个对象的引用则存储在stack里。程序通过stack里的引用找到这个对象。例如var a = [1,2,3];,a是存储在stack里的引用,heap里存储着内容为[1,2,3]的Array对象。

    在这里我们引出调用栈的概念
    也就是你所写的JS代码是如何执行的,不多逼逼,看代码

    function a() {
      console.log('a')
       //console.trace()
    }
    
    function b() {
      a()
    }
    
    function c() {
      b()
    }
    
    c()
    

    这段简单的代码,相信都能看出来调用都顺序

    • 在全局调用了 c()
    • c 调用了 b
    • b 调用了 a
    • a 调用了console
      换成在调用栈就是:如图 ⬇️


      callstack.png
    • global => c => b => a => console依次进栈
      运行完毕后出栈
    • console => a => b => c => global依次出栈
      :可以用console.trace() 在控制台看到调用栈

    嗯哼,很简单吧
    how about

    console.log('start')
    
    setTimeout(function(){
      console.log('setTimeout')
    }, 100)
    
    sleep(100000000)
    
    console.log('end')
    

    这就要说到js异步处理了,为啥要用异步?同步(按照代码执行顺序)执行,setTimeout 100000000,空闲的cpu就要一直等待100000000ms,才继续执行任务,巨大的资源浪费明显是不合理的。so
    在这里我就直接给出答案了,反正你们打开控制台也能直接看到了

    //start
    //end 
    //setTimeout
    

    那么

    console.log('start')
    
    setTimeout(function(){
      console.log('setTimeout 100')
    }, 100)
    
    setTimeout(function(){
      console.log('setTimeout 0')
    }, 0)
    
    console.log('end')
    

    是0先输出呢还是100呢?
    这样?

    console.log('start')
    
    setTimeout(function(){
      console.log('setTimeout 1')
      setTimeout(function(){
        console.log('setTimeout 3')
      }, 0)
    }, 0)
    
    setTimeout(function(){
      console.log('setTimeout 2')
    }, 1000)
    
    console.log('end')
    

    异步在栈里面是如何调用的?
    其实一个图就能看懂了

    image.png
    • V8 遇到异步函数,函数进栈
    • call back 交给WebAPIs
    • 函数出栈
    • 继续执行代码
      ...
    • WebAPI判定可以执行了
    • call back 进入回调队列
    • 代码执行完毕,栈清空
    • 队列依次进栈

    相关文章

      网友评论

          本文标题:JavaScript 运行机制 Event loop

          本文链接:https://www.haomeiwen.com/subject/yytamxtx.html