V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
find456789
V2EX  ›  问与答

js 只有一个线程,那么用了异步,等待 io 的时候,不用消耗线程吗?没有一个守护线程去等待 io 吗

  •  
  •   find456789 · 2020-04-30 14:42:09 +08:00 · 1360 次点击
    这是一个创建于 1674 天前的主题,其中的信息可能已经有所发展或是发生改变。

    看到网上说 js 只有一个线程

    那么我理解 js 同时只能做一件事

    如果这个线程 同步去请求一个图片, 如果网络很卡, 那么其他地方就会卡住, 因为没有线程去处理其他地方

    可是我看到网上说, 用来异步就可以解决这个问题

    我的理解是: 用了异步后, 发起请求后,这个线程继续处理 ui,处理其他事情 , 等 io 请求返回结果以后,线程就切换到原来的地方,对 io 结果进行处理

    可是,js 怎么知道 io 请求完毕 了呢? 难道不用起一个新线程,专门请求 io 吗? 或者监听 io 请求状态吗

    谁告诉 js 这个 io 请求完毕了呢? 操作系统吗? 或者 其他的

    谢谢

    7 条回复    2020-04-30 15:55:48 +08:00
    754181906aaa
        1
    754181906aaa  
       2020-04-30 14:47:00 +08:00   ❤️ 1
    js 的单线程是对开发者而言的,就是你的代码运行在单线程上, 但是浏览器并不是单线程, 像 v8, 磁盘 io 就是用的线程池, 网络 io 是 epoll 。
    shintendo
        2
    shintendo  
       2020-04-30 14:48:16 +08:00   ❤️ 1
    js 调用浏览器的 api 发送请求,具体的发送和接收是浏览器的事情
    Mozshaw
        3
    Mozshaw  
       2020-04-30 14:56:37 +08:00   ❤️ 1
    这些是 Web API,io 请求完毕后会把回调放到 Task Queue 里。然后 JS 会通过 event loop 去循环的检测调用栈是否是空的,当调用栈空了之后就会从队列里取出回调,压入调用栈执行
    find456789
        4
    find456789  
    OP
       2020-04-30 15:47:26 +08:00
    @Mozshaw
    @shintendo
    @754181906aaa

    ========

    谢谢

    我的新理解如下:

    当我用浏览器打开一个网页后, 浏览器引擎会把代码捋一捋,把代码里所有方法 放入 堆栈里,也就是 task Queue

    js 线程就像一个工人,

    而 task Queue 就是工作列表,

    工人开始工作后,就去 task Queue 领取一份工作,先领取上面的任务(先进后出, 后进先出,先安排的任务后做,后安排的任务先做)

    工人做完一份工作后,这个工作就从 task Queue 里删除了(从堆栈里弹出了)

    然后工人继续领取下一份工作

    其中有一份工作是,发起一个异步 io 操作,工人领取了,并执行了这个 api,工人完成了发起请求的工作,于是继续领取下一份工作

    工人执行的那个 api 就是让浏览器去请求数据,这时候浏览器就去请求数据,

    在浏览器请求数据的过程中, 工人还是继续领任务、做任务,每做完一个任务,浏览器就会把这个任务从 task Queue 里删掉


    一段时间后(可能几十毫秒),浏览器得到了 io 数据,然后把 io 数据,和处理 io 数据的代码放在 task Queue 列表的最上面, 等待工人下一次来领取这个任务

    后来,工人做完了手上的工作,又来领取新工作, 就领取到了这个 带有 io 数据的任务, 然后 工人就按照代码对这个 io 数据进行处理、加工


    请问我的理解对吗
    m0cha
        5
    m0cha  
       2020-04-30 15:54:02 +08:00 via iPhone   ❤️ 1
    @find456789 这学期刚上了这门课,这理解是对的,所谓的 nodejs 单线程就是指,这个工人领任务和做任务是单线程的,至于浏览器 wjiqio 是由另外的线程完成的
    m0cha
        6
    m0cha  
       2020-04-30 15:54:24 +08:00 via iPhone   ❤️ 1
    @m0cha 浏览器完成 io
    fengfuliu
        7
    fengfuliu  
       2020-04-30 15:55:48 +08:00   ❤️ 2
    在执行代码过程中,如果遇到一些异步代码(比如 setTimeout,ajax,promise.then 以及用户点击等操作),那么浏览器就会将这些代码放到另一个线程(在这里我们叫做幕后线程,这个线程可能存在于浏览器或 js 引擎内,与主线程是分开的,处理文件读取、网络请求等异步事件。)中去执行,在前端由浏览器底层执行,在 node 端由 libuv 执行,这个线程的执行不阻塞主线程的执行,主线程继续执行栈中剩余的代码。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2936 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 03:24 · PVG 11:24 · LAX 19:24 · JFK 22:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.