zoukankan      html  css  js  c++  java
  • 同步任务和异步任务

    同步和异步操作的区别就是是否阻碍后续代码的执行。

    同步任务是那些没有被引擎挂起、在主线程上排队执行的任务。只有前一个任务执行完毕,才能执行后一个任务。

    异步任务是那些被引擎放在一边,不进入主线程、而进入任务队列的任务。只有引擎任务某个异步任务可以执行了(比如Ajax操作从服务器得到了结果)【发布订阅】,该任务(采用回调函数形式)才会进入主线程执行。排在异步任务后面的代码,不用等待异步任务结束会马上运行,也就是说,异步不具有“堵塞”效应。

    在setTimeout的执行形式上来看,setTimeout是不会阻碍其后续代码的执行的。所以可以理解为setTimeout是异步操作。

    单线程模式

    js是单线程的,但JS运行环境(Chrome浏览器)是多线程的。

    image

    GUI线程

    GUI线程就是渲染页面的,负责解析HTML和CSS,然后将她们构建成DOM树和渲染树就是这个线程负责的。

    JS引擎线程

    这个线程就是负责执行js的主线程,前面说的“JS是单线程的”就是指的这个线程。V8引擎就是在这个线程运行。需要注意的是,这个线程跟GUI线程是互斥的。互斥的原因是JS也可以操作DOM,如果JS线程和GUI线程同时操作DOM,结果就混乱了,不知道到底渲染哪个结果。这带来的后果就是如果JS长时间运行,GUI线程就不能执行,整个页面就感觉卡死了。所以我们最开始例子的while(true)这样长时间的同步代码在真正开发时是绝对不允许的。

    定时器线程

    定时器线程其实只是一个计时的作用,它并不会真正执行事件到了的回调,真正执行这个回调的还是Js主线程。所以当时间到了定时器线程会将这个回调事件给到事件触发线程,然后事件触发线程将它加到任务队列里面去。最终JS主线程从任务队列取出这个回调执行。事件触发线程不仅会将定时器事件放入任务队列,其他满足条件的事件也是由它负责放进任务队列。

    异步HTTP请求线程

    这个线程负责处理异步的Ajax请求,当请求完成后,它也会通知事件触发线程,然后事件触发线程将这个事件放入任务队列给主线程执行。

    所以异步的实现靠的就是浏览器的多线程,当他遇到异步API时,就将这个任务交给对应的线程,当这个异步API满足回调条件时,对应的线程又通过事件触发线程将这个事件放入任务队列,然后主线程从任务队列取出事件继续执行。 这个流程我们多次提到了任务队列,这其实就是Event Loop。

    image

    任务队列(Event Loop)
    JavaScript 运行时,除了一个正在运行的主线程,引擎还提供多个任务队列(根据任务的类型,所以有多个)。

    首先,主线程会去执行所有的同步任务。等到同步任务全部执行完,就会去看任务队列里面有没有事件回调。如果有,则取出就重新进入主线程执行,这时它就变成同步任务了。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。

    异步任务的写法通常是回调函数。一旦异步任务重新进入主线程,就会执行对应的回调函数。如果一个异步任务没有回调函数,就不会进入任务队列,也就是说,不会重新进入主线程,因为没有用回调函数指定下一步的操作。

    只要同步任务执行完了,引擎就会一遍又一遍地去检查那些挂起来的异步任务,是不是可以进入主线程了。这种循环检查的机制,就叫做事件循环(Event Loop)

    目前JS的主要运行环境有两个——浏览器和Node.js。相比于V8引擎,node 中增加了两种异步方式: process.nextTick() 和 setImmediate()。

    Node 规定,process.nextTick()和Promise的回调函数,追加在本轮循环,即同步任务一旦执行完成,就开始执行它们。

    而setTimeout、setInterval、setImmediate的回调函数,追加在次轮循环。

    process.nextTick()
    追加到本轮循环执行,而且是所有异步任务里面最快执行的,nextTickQueue。

    Promise异步
    image
    Promise的回调函数不是正常的异步任务,而是微任务(microtask)。它们的区别在于,正常任务追加到下一轮事件循环,微任务队列追加在process.nextTick队列的后面,也属于本轮循环
    image

    Nodejs事件循环的六个阶段
    首先,事件循环是在主线程上完成的。其次,脚本开始执行时,事件循环只进行了初始化,并没有开始。只有当下面事件执行完毕后,事件循环才会开始。

    • 同步任务
    • 发出异步请求
    • 规定定时器生效的事件
    • 执行process.nextTick()等等
      事件循环会无限次地执行,一轮又一轮。只有异步任务的回调函数队列清空了,才会停止执行。
      每一轮的事件循环,分成六个阶段。

    timers:定时器阶段,处理setTimeout()和setInterval()的回调函数。进入这个阶段后,主线程会检查一下当前时间,是否满足定时器的条件。如果满足就执行回调函数,否则就离开这个阶段。
    I/O callbacks:除了以下操作的回调函数,其他的回调函数都在这个阶段执行。【setTimeout()和setInterval()的回调函数;setImmediate()的回调函数;用于关闭请求的回调函数,比如socket.on('close', ...)】
    idle, prepare:这个阶段是轮询时间,用于等待还未返回的 I/O 事件,比如服务器的回应、用户移动鼠标等等。
    这个阶段的时间会比较长。如果没有其他异步任务要处理(比如到期的定时器),会一直停留在这个阶段,等待 I/O 请求返回结果。

    poll:这个阶段是轮询时间,用于等待还未返回的 I/O 事件,比如服务器的回应、用户移动鼠标等等。
    check:该阶段执行setImmediate()的回调函数。
    close callbacks:该阶段执行关闭请求的回调函数,比如socket.on('close', ...)
    每个阶段都有一个先进先出的回调函数队列。只有一个阶段的回调函数队列清空了,该执行的回调函数都执行了,事件循环才会进入下一个阶段。

  • 相关阅读:
    windows10家庭版安装docker踩坑解决记录
    sequelize Getters, Setters & Virtuals
    sequelize模型增删改查询(基础)Model Querying
    sequelize数据库模型关联文档详解
    Nginx配置实现下载文件
    Linux常用命令记录
    nodejs后台如何请求第三方接口request-promise简介及其废弃后的替代方案推荐got、axios
    新版本chrome浏览器(80版本以后)带来的跨域请求cookie丢失问题
    谷歌浏览器 Cookie 的 SameSite 属性 (转)
    JavaScript Image对象 整理
  • 原文地址:https://www.cnblogs.com/huayang1995/p/15655467.html
Copyright © 2011-2022 走看看