JavaScript事件循环怎么使用

寻技术 JS脚本 / JAVA编程 2023年11月27日 114

这篇文章主要讲解了“JavaScript事件循环怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript事件循环怎么使用”吧!

JavaScript事件循环是一种机制,用于处理异步事件和回调函数。它是JavaScript运行时环境的一部分,负责管理事件队列和调用栈。

事件循环的基本原理是事件循环的核心是一个事件队列,所有的事件都被放入这个队列中,然后按照顺序依次执行。如果队列为空,JavaScript会等待新的任务加入队列。当JavaScript代码执行时,所有同步任务都会被立即执行,而异步任务则会被放入事件队列中。

当所有同步任务执行完毕后,事件循环会从事件队列中取出一个任务,并将其放入调用栈中执行。当该任务执行完毕后,事件循环会再次从事件队列中取出下一个任务,并重复这个过程。

一、事件循环的执行过程

1、执行同步代码,直到遇到第一个异步事件(如setTimeout、setInterval、Promise等)。

2、将异步事件放入事件队列中,并继续执行同步代码。

3、当所有同步代码执行完毕后,JavaScript引擎会检查事件队列中是否有事件需要执行。

4、如果事件队列中有事件需要执行,JavaScript引擎会将第一个事件取出来,并执行对应的回调函数。

5、执行完回调函数后,JavaScript引擎会再次检查事件队列中是否有事件需要执行,如果有则重复步骤4,否则继续等待新的事件加入事件队列。

需要注意的是,事件循环是单线程的,也就是说JavaScript引擎在同一时间只能执行一个任务。

因此,如果一个任务执行时间过长,会阻塞事件循环,导致其他任务无法执行。为了避免这种情况,可以将长时间的任务拆分成多个小任务,使用setTimeout或setInterval分批执行。

另外,Promise也是基于事件循环的机制实现的。当Promise状态发生改变时,会将对应的回调函数放入微任务队列中,等待当前任务执行完毕后立即执行。因此,Promise的回调函数总是在当前任务执行完毕后立即执行,而不会被放入事件队列中等待执行。

二、事件循环进阶用法

1、

Promise
:Promise是一种异步编程的解决方案,它可以将异步操作转化为同步操作的形式,使得代码更加简洁易懂。Promise的基本原理是将异步操作封装成一个Promise对象,通过then方法来处理异步操作的结果。

2、

async/await
:async/await是ES2017引入的一种异步编程的解决方案,它可以让异步代码看起来像同步代码,使得代码更加易读易懂。async/await的基本原理是使用async关键字定义一个异步函数,然后在函数内部使用await关键字来等待异步操作的结果。

3、定时器:JavaScript中有两种定时器,分别是setTimeout和setInterval。setTimeout用于在指定的时间后执行一次任务,而setInterval则用于每隔一段时间执行一次任务。这两种定时器都是异步任务,会被放入任务队列中等待执行。

三、JavaScript任务类型

JavaScript中的任务按照不同纬度进行区分主要分为同步任务和异步任务、宏任务和微任务。

3.1 同步任务&异步任务

1、 同步任务按照代码顺序执行的任务。

2、 异步任务是在将来某个时间点执行的任务。异步任务通常是由事件触发器(如鼠标点击、网络请求等)生成的。 当一个异步任务被触发时,它会被放入任务队列中等待执行。

JavaScript事件循环的执行顺序可以用以下伪代码表示:

while (queue.waitForMessage()) { 
    queue.processNextMessage(); 
}

在这个伪代码中,

queue.waitForMessage()
表示等待队列中有待执行的任务,
queue.processNextMessage()
表示取出队列中的下一个任务并执行。

需要注意的是,JavaScript事件循环的执行顺序是不可中断的。这意味着当一个任务正在执行时,其他任务必须等待,直到当前任务完成。因此,如果一个任务执行时间过长,会导致其他任务无法及时执行,从而影响应用程序的性能和响应速度。

3.2 宏任务&微任务

1、宏任务包括setTimeout、setInterval、I/O操作等。

2、微任务包括Promise、MutationObserver等。

当事件循环从事件队列中取出一个任务时,它会先执行所有微任务,然后再执行一个宏任务。这个过程会一直重复,直到事件队列中的所有任务都被执行完毕。

下面是一个例子:

console.log('1'); 

setTimeout(function() { 
    console.log('2'); 
    Promise.resolve().then(function() { 
        console.log('3'); 
    }); 
}, 0); 

Promise.resolve().then(function() { 
    console.log('4'); 
}); 
console.log('5'); 

// 输出结果为: 1 5 4 2 3

执行顺序:

  • 执行第一个

    console.log
    ,输出1。
  • 执行

    setTimeout
    ,将其回调函数放入宏任务队列中。
  • 执行

    Promise.resolve().then
    ,将其回调函数放入微任务队列中。
  • 执行第二个

    console.log
    ,输出5。
  • 当前任务执行结束,执行微任务队列中的所有任务,输出4。

  • 执行宏任务队列中的第一个任务,即

    setTimeout
    的回调函数,输出2。
  • 执行

    Promise.resolve().then
    的回调函数,输出3。

需要注意的是,微任务和宏任务的执行顺序是固定的,即先执行所有微任务,再执行宏任务。因此,如果在一个宏任务中产生了新的微任务,那么这些微任务会在下一个宏任务执行之前执行。

下面是一个例子:

console.log('1'); 

setTimeout(function() { 
    console.log('2'); 
    Promise.resolve().then(function() { 
        console.log('3'); 
    }); 
}, 0); 

Promise.resolve().then(function() { 
    console.log('4'); 
    setTimeout(function() { 
        console.log('5'); 
    }, 0); 
}); 

console.log('6'); 

// 输出结果为:1 6 4 2 3 5

执行顺序:

  • 执行第一个

    console.log
    ,输出1。
  • 执行

    setTimeout
    ,将其回调函数放入宏任务队列中。
  • 执行

    Promise.resolve().then
    ,将其回调函数放入微任务队列中。
  • 执行第三个

    console.log
    ,输出6。
  • 当前任务执行结束,执行微任务队列中的所有任务,输出4。

  • 执行宏任务队列中的第一个任务,即

    setTimeout
    的回调函数,输出2。
  • 执行

    Promise.resolve().then
    的回调函数,将setTimeout的回调函数放入宏任务队列中。
  • 当前任务执行结束,执行微任务队列中的所有任务,输出3。

  • 执行宏任务队列中的第一个任务,即

    setTimeout
    的回调函数,输出5。
关闭

用微信“扫一扫”