粗略理解 JavaScript的eventLoop

    科技2024-03-28  65

    我们都知道JavaScript是单线程的语言,也就是在同一时间只能做一件事,就好比去银行办事,银行确只有一个办事窗口,人们必须一个一个排队,那么为什么要将JavaScript设计成单线程语言呢?我在网上大致看了下,基本上都是这么说的:

    JavaScript作为浏览器脚本语言,如果采用多线程的设计方式,会产生一部分复杂的问题,举个例子就是两个线程同时操作一个DOM元素,一个线程是删除这个DOM元素,另一个线程是修改这个DOM,那么要以那个线程为准呢?

    大致上都是这样的说法;

    然而。。在HTML5中出现了一个API :Web Worker,他允许JavaScript在主线程以外另外创建一个线程,但是这个创建的线程不允许操作DOM元素而且还是完全受控于主线程的,所以这个API实际上并没有改变JavaScript是单线程的这一个特性;

    单线程意味着要排队,那么如果遇到了不确定耗时的任务怎么办呢?比如说现在我要发送一个请求,但是这个请求 往返的时间是不确定的,在请求的这段时间,难道要让用户一直等着吗?这对于用户的体验来说是十分不妙的,于是 同步和异步的概念就出来了,那么什么是同步,什么是异步呢?所谓的同步任务就是,老老实实的在主线程中排队执 行的事件;异步任务则是先不执行,而是将任务放入事件队列中,等待同步任务执行完成之后再回过头来执行事件队 列中的异步任务;

    大致上的是这样的,比方说我们一起执行两个函数,第一个函数中有一个同步操作与一个异步操作,然后第二个函数中有一个异步操作

    let fn1 = function(){ setTimeout( () => { console.log('函数一:异步'); },0); console.log('函数一:同步'); }, fn2 = function(){ setTimeout( () => { console.log('函数二:异步') },0) }; fn2(); fn1(); // 输出 '函数一:同步' -> '函数二:异步' -> '函数一:异步'

    从这段代码中我们可以看到的是:

    在代码中我们先执行的是 fn2 这个函数,但是在这个函数中只有异步的定时器操作,所以JS将这个操作暂时存 入事件队列中,转而去执行了函数 fn1 ,在 fn1 函数中 'console.log('函数一:同步')';这一段是同步操作, 所以就算 setTimeout 定义在前面,JS 也会先将定时器存到事件队列中,去执行 'console.log('函数一:同步')' 这一段操作;也就是说这两个函数执行下来,JS的主线程中是只有 'console.log('函数一:同步')';这一段代码; 而在执行完这段之后,在查看主线程时,JS发现主线程的执行栈中已经没有待执行事件了,就转而去事件队列中将异 步事件,拉入执行栈中执行,由于先执行的 fn2 函数,所以先打印 '函数二:异步',最后打印 '函数一:异步';

    然而在异步任务中,又分为了宏任务和微任务两种;

    宏任务

    定时器,AJAX; 这一类任务被定义为宏任务,宏任务的执行顺序是排在了微任务后;

    微任务

    Promise 的 then 就是微任务,但是要注意 new Promise中的操作是同步的操作;

    所以最终的执行顺序是 同步 > 异步 ; 异步中: 微任务 > 宏任务;

    总的来说: 同步任务 > 微任务 > 宏任务;宏任务与微任务归类到异步任务中;
    Processed: 0.013, SQL: 8