V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
yazoox
V2EX  ›  JavaScript

有关 Javascript 的 event loop 和 async function,我始终没有弄明白。

  •  
  •   yazoox · 353 天前 · 870 次点击
    这是一个创建于 353 天前的主题,其中的信息可能已经有所发展或是发生改变。

    就是这个异步函数到底是在立即执行(在后台另外一个线程中),然后把 callback 函数放到 event loop 的 task queue 中去,还是这个异步函数本身就被放到了 task queue 中去了,然后再下一次 event loop 中执行?

    如果是前者,Javascript 不是单线程的么?还有其它的线程执行异步函数?

    如果是后者,这个异步函数如果需要执行很长时间,比如 fetch 一个文件,那不是就会阻塞了 main thread ,页面就会卡住了?

    比如:

    const fetchData = () => {
      return new Promise((resolve, reject) => {
        fetch('https://api.example.com/data')
          .then(response => response.json())
          .then(data => resolve(data))
          .catch(error => reject(error));
      });
    };
    
    fetchData()
      .then(data => console.log('Data:', data))
      .catch(error => console.error('Error:', error));
    

    当 fetchData 被执行的时候,里面的fetch这个函数(异步函数),是被放到 backend thread 里面去执行了,然后它的 callback/then then(response => response.json()) 被会放 task queue 里面去?就是说除了 main thread ,还有很多其它 threads 了?( chatGPT 是这么解释的,说 Web API 都是由浏览器在 backend 后面开 thread 执行,但我不知道它是不是又在胡说八道......) 如果这个 fetch 需要花很多时间,在下一次 event loop 循环到的时候,还没有运行完,那它的 callback/then 咋整?

    所以,我这个 Javascript 的 event loop & async function 的关系犯迷糊了,绕不出来了。

    Fetch API is a promose-based https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

    jifengg
        1
    jifengg  
       353 天前
    楼主,有些问题我没法回答你,但是有些还是可以说说。

    “JavaScript 单线程”,是指,“你写的代码”,永远只有一处被执行。而 JavaScript 引擎本身是多线程的,event loop 就是引擎用额外的线程来管理的,而且 event loop 里其实也分了“微任务( micro task )和宏任务( macro task )”

    另一个,“执行很长时间”你用 fetch 来举例是不恰当的,因为 fetch 也是异步函数( IO 异步),它不会阻塞 main thread ;要真正阻塞 js ,你必须用 cpu 密集型的代码才行(也就是让你的代码一直在被执行不停歇),比如 for(var i;i<100000000000;i++);
    CLMan
        2
    CLMan  
       353 天前
    1. 应该是后者吧,`fetch`是个 Promise API ,不会阻塞 main thread 。

    2. 真要完全弄清楚的话,你始终在 JavaScript 层面思考是没用的,因为计算机软件是分层的,每层向上提供封装,特别是 io 、线程之类的,并没有完全屏蔽底层并提供完备抽象的封装。你要去研究浏览器实现,去研究 OS API 实现,去研究硬件实现,但没有相关知识储备的话,这个过程效率极低,量力而行。
    hsir
        3
    hsir  
       342 天前
    你打印一下 fetch.toString(),会得到 function fetch() { [native code] }。这个 API 调用后就是浏览器自己的某个其他 thread 去请求了,进行到这一步,JS 线程不会等,会继续做其他的事情。直到浏览器请求完成,拿到 fetch result 后,主动把这个 result 告诉 JS ,于是 JS 就可以跑你的 then 逻辑了。
    daolanfler
        4
    daolanfler  
       337 天前
    <iframe width="560" height="315" src="https://www.youtube.com/embed/8aGhZQkoFbQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
    daolanfler
        5
    daolanfler  
       337 天前
    @daolanfler


    这两个视频看一下就能有个概念了
    ChanKc
        6
    ChanKc  
       335 天前 via Android
    1 楼说的不对,js 就是单线程的,除非你用 worker 。event loop 就是一个线程的事情。
    fetch 比较复杂,不建议你用 fetch 去理解 event loop 。
    fetch 实际上会调起一个你 js 代码无法控制的线程(下面简称网络线程)去执行 http 请求。直到 http 响应前,任务队列里都是空的。响应后网络线程会通知主线程,主线程执行 then(someTask),会把 someTask 放入队列(但不会马上执行,直到下一次队列检测时)。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2890 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 07:10 · PVG 15:10 · LAX 00:10 · JFK 03:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.