JavaScript——事件循环模式

本文深入解析JavaScript的事件循环机制,包括函数调用栈、堆和任务队列。详细阐述了宏任务与微任务的执行顺序,通过示例解释setTimeout和Promise在事件循环中的行为。同时,介绍了如何避免长任务导致的用户交互阻塞,以及如何理解异步编程中的async/await和Promise。
摘要由CSDN通过智能技术生成

1,了解JS事件循环、代码执行顺序,先了解运行时的函数调用栈(Stack)、堆(Heap)和任务队列(queue,有微任务队列和宏任务之分);(注:以下的理解不够深入,日后有机会再探讨)

Stack:栈的特点是先进后出,推进栈的每一个元素称为帧,每个函数的执行将作为一个帧被推进栈中,当函数执行完毕,那么该帧就会出栈,所以所谓的栈也就是函数调用栈;当栈的所有函数执行完毕,栈也就清空,JS会执行Queue中下一个任务并将其推进栈中;

Heap:堆是散列的,用来表示一大块的内存区域,对象被分配在堆中;

Queue:队列的特点是先进先出,消息队列或者说任务队列,每个消息都有一个相关联的回调(函数回调);队列可分为两种,微任务队列(指小型消息回调,如promise的回调和事件触发的监听器回调,会放入微任务队列)和宏任务队列(相对微任务来说,如setTimeout和setInterval的回调会放入宏任务队列),当微任务队列没有任务需要执行时,会立即执行宏任务队列的任务,当微队列有不止一个任务(该类型的回调不管是否在执行该队列的任务,新加的任务都会直接插入队列,并在该次事件循环中被调用),那么会把所有的任务都执行完毕才会去执行宏队列的一个任务;不管怎样,当遇到执行时间比较长的任务时,会阻塞用户的交互,这时要考虑分成几个更小的任务;每一个消息的执行都是上一次栈被清空后的开始,即上一个消息的执行完毕;有点需要注意的是,当此时此刻需要被执行的任务才会放入队列中,其他的任务就像是放在等待区一样,没到时间则不会进入队列中;

事件循环:类似于

//
while(true){
     while(queue.waitForMessage()){
        queue.processNextMessage(); //会先优先处理微任务
    }       
}

setTimeout, setInterval, Promise(异步函数):

setTimeout(fn | 'code string', delay, ...args); setInterval(fn | 'code string', delay, ...ars);new Promise(fn).then(fn, fn).then(fn, fn)....catch(fn).finally(fn);

setTimeout和setInterval: 一般不使用 'code string' 的形式作为回调,因为不安全不易于调试(可能还有其他问题?);args是在回调函数调用时,做回调函数的参数的,一般不这样使用,因为存在兼容性问题;以下例子展示了代码执行顺序;

//
console.log('Start');
//宏任务1
setTimeout(function(){ //延迟时间默认为 0,立即放入宏任务队列中;
    console.log('setTimeout callback 1');
});

var pro = new Promise(function(resolve){
    //宏任务2
    setTimeout(()=>{ //延迟时间默认为 0,立即放入宏任务队列中;
        console.log('setTimeout callback 2');
        resolve(true)
    });
});

//微任务1
pro.then(function(){ //被放入微队列等待区,promise的状态变为fullfilled时,
                       //该回调放入队列中,等待调用;
    console.log('promise callback 1');
    //微任务3
    pro.then(function(){ //promise的状态已是fullfilled时,该回调放入队列中,等待调用;
        console.log('promise callback 2');
    });

    console.log('promise callback 1 end');
});

//微任务2
pro.then(function(){//被放入微队列等待区,promise的状态变为fullfilled时,
                        //该回调放入队列中,等待调用;
   console.log('promise callback 3'); 
});

//宏任务3
setTimeout(function(){
    console.log('setTimout callback 3');
});

var i = 0;
var test = setInterval(function(){
    console.log('hihi');
    i++;
    if(i> 2){
        clearInterval(test);
    }
},1000);

console.log('end');
//JS会先把这段执行完毕,微队列暂时没有任务,Start
//执行结果:
//Start
//end
//--------该函数调用结束,调用栈被清空,进入下一次事件循环; 此时微队列没有任务待调用,
//宏队列有任务待调用:宏任务1、2、3
//setTimeout callback 1
//setTimeout callback 2   
//-------------resolve(true), 之后,promise的回调被推入微队列中,在一次事件循环,
//调用微队列的任务:微任务1、2、3
//promise callback 1
//promise callback 1 end
//promise callback 3
//promise callback 2
//-------在下一次事件循环中,微队列已空,调用宏队列的任务,此时剩下宏任务3;
//setTimout callback 3
//-----setInterval执行之后1秒钟,第一个setInterval回调进入宏任务等待调用
//hihi
//------又1秒之后
//hihi
//----又1秒之后
//hihi

2,其他文档:

Async awiat/Promise

3,参考文档:

JS事件循环

JS内存管理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值