美文网首页
浏览器原理-事件循环机制

浏览器原理-事件循环机制

作者: 9吧和9说9话 | 来源:发表于2020-02-26 10:05 被阅读0次

    浏览器的渲染进程的主线程承担着大量的任务:DOM解析,javascript的解析执行,样式计算、布局渲染,接收用户事件等等。那么是如何工作的呢?

    事件循环机制

    1. 主线程不断的循环处理一个消息任务队列
    2. IO线程负责接收其他的线程以及其他的进程发送过来的任务。
    3. 为了保证某些任务的特殊需求:实时性和主线程的执行效率,每一个消息队列中的任务都有一个微任务队列, 例如我们的promisemutationObserver都会被添加到微任务队列中。这样在当前的任务执行完成之前,会触发自己微任务队列的处理。避免了直接将微任务添加到消息队列队尾造成的实时性不足的问题。
    4. 如何安全的推出当前主线程:chrome是在确定推出当前页面之前,设置了一个标记变量,主线程循环中每次执行完任务就会判断当前的标记是否为真,如果是就跳出循环,结束线程执行。
    5. setTimeout是如何执行的:有一个延时任务列表(内部结构是HashMap),用来存放需要延时执行的任务。
      为啥不能直接将延时任务放到消息队列中呢:因为消息队列是按照顺序执行的,无法做到在指定的延时时间之后执行任务。
      延时任务列表是怎么做到的呢
      延时任务列表中的任务结构大致如下:
    // 记录了当前执行的任务、开始计时时间、延时时间、以及任务ID(就是我们的setTimeout的返回值)
    struct DelayTask{
      int64 id;
      CallBackFunction cbf;
      int start_time;
      int delay_time;
    };
    DelayTask timerTask;
    timerTask.cbf = showName;
    timerTask.start_time = getCurrentTime(); //获取当前时间
    timerTask.delay_time = 200;//设置延迟执行时间
    

    在主线程循环处理消息队列消息中,处理完成当前的任务之后(包括当前任务的微任务),就会执行延时任务触发检测,查看当前延时任务列表中的任务哪些达到了延时时间间隔,就会执行这些延时任务。

    
    void ProcessTimerTask(){
      //从delayed_incoming_queue中取出已经到期的定时器任务
      //依次执行这些任务
    }
    
    TaskQueue task_queue;
    void ProcessTask();
    bool keep_running = true;
    void MainTherad(){
      for(;;){
        //执行消息队列中的任务
        Task task = task_queue.takeTask();
        ProcessTask(task);
        
        //执行延迟队列中的任务
        ProcessDelayTask()
    
        if(!keep_running) //如果设置了退出标志,那么直接退出线程循环
            break; 
      }
    }
    
    事件循环机制 图片来源:极客时间

    XMLHttpRequest 是如何执行的

    XMLHttpRequest 工作流程图 图片来源:极客时间

    代码示例:

    
     function GetWebData(URL){
        /**
         * 1:新建XMLHttpRequest请求对象
         */
        let xhr = new XMLHttpRequest()
    
        /**
         * 2:注册相关事件回调处理函数 
         */
        xhr.onreadystatechange = function () {
            switch(xhr.readyState){
              case 0: //请求未初始化
                console.log("请求未初始化")
                break;
              case 1://OPENED
                console.log("OPENED")
                break;
              case 2://HEADERS_RECEIVED
                console.log("HEADERS_RECEIVED")
                break;
              case 3://LOADING  
                console.log("LOADING")
                break;
              case 4://DONE
                if(this.status == 200||this.status == 304){
                    console.log(this.responseText);
                    }
                console.log("DONE")
                break;
            }
        }
    
        xhr.ontimeout = function(e) { console.log('ontimeout') }
        xhr.onerror = function(e) { console.log('onerror') }
    
        /**
         * 3:打开请求
         */
        xhr.open('Get', URL, true);//创建一个Get请求,采用异步
    
    
        /**
         * 4:配置参数
         */
        xhr.timeout = 3000 //设置xhr请求的超时时间
        xhr.responseType = "text" //设置响应返回的数据格式
        xhr.setRequestHeader("X_TEST","time.geekbang")
    
        /**
         * 5:发送请求
         */
        xhr.send();
    }
    

    相关文章

      网友评论

          本文标题:浏览器原理-事件循环机制

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