javascript-for循环和setTimeout的特殊样例

前提

事件循环机制:同步任务解决完,在解决异步的(即是任务队列里的)

首先明确概念:任务分为微任务和宏任务,任务队列里面的任务都是宏任务(setTimeout,定时器,ajax,DOM操作),微任务:then(),只有一个微任务队列,任务队列(宏任务队列)可以有多个;微任务全部执行完后才执行宏任务。

细致:同步代码执行完,首先会看看微任务队列中是否存在微任务,有的话就是取出来到主线程中执行,否则从任务队列中取出主任务到主线程执行。如果这时候,正在执行的宏任务产生了一个微任务,那么这个微任务放到微任务队列中,等待主线程上的宏任务执行完后,执行微任务。

在两次宏任务的之间,浏览器会对页面重新进行渲染,所以如果在第一次宏任务执行时,产生了微任务,在页面渲染之前,会先执行微任务,然后进行页面渲染,然后接着下一次的宏任务。

样例一

console.log(11);
for (var i = 0; i < 4; i++) {
    
    
    setTimeout(console.log(i), 1000); // 立即执行,注意console.log()相当于一个立即执行函数
}
console.log(222);
/**
  效果:直接执行,且没有等待delay时间,所以这个setTimeout没有进入任务队列        
11
0
1
2
3
222
 */

样例二

console.log(111);
for(let i=0; i<4; i++){
    
      // 使用let关键字
    setTimeout(()=>{
    
    
        console.log(i);
    },1000);
}
console.log(222);
/*
效果:延时器等待了1s后,全部打印出来,并没有我之前想象的隔一秒输出一个
其实是创建了多个延时器,大家同步执行,都等待了1s后,然后放入任务队列中,最后从任务队列中一个一个输出
但是js运行速度太快,然后差不多同一时间4个数都输出来
111
222
0
1
2
3
*/

样例三

console.log(111);
for (var i = 0; i < 4; i++) {
    
    
    setTimeout("console.log(i)", 1000);  // 第一个参数是字符串
    // 如果setTimeout第一个参数字符串的话,那么在delay毫秒之后编译和执行字符串
    //(不建议)使用,不建议使用eval(),eval()参数是字符串,功能是编译执行参数的字符串
}
console.log(222);
/*
效果:等待一秒后,同时输出4个4,
解释:官方文档:setTimeout第一个参数是字符串的话,那么在delay之后编译和执行字符串,所以打印出4个4
至于为啥是4个4和等待一秒后,原因就是var和创建了4个setTimeout,同步执行
111
222    
4
4
4
4
*/

事件循环机制样例一

注意的点就是then被分到微任务队列中时,then()里面的代码还没有执行

new Promise()参数里面的代码是同步代码

new Promise((resolve) => {
    
    
    console.log('new Promise(macro task 1)');
    resolve();
}).then(() => {
    
                           
    // 微任务生成宏任务,then首先被分到微任务队列中,但此时里面的setTimeout还没有被分到宏任务中
    // then里面的代码还没有被执行
    // 当同步代码执行完后,执行微任务队列中的所有代码,这是,setTimeout就被分到了宏任务队列中
    console.log('micro task 1');
    setTimeout(() => {
    
    
        console.log('setTimeout1');
    }, 0)
})

setTimeout(() => {
    
           
    // 宏任务,先与上面分配到宏任务中,所以先输出setTimeout2,在输出setTimeout1
    //要注意setTimeout这两个函数的delay参数相同,如果不同,顺序也不同
    console.log('setTimeout2');
}, 0)

console.log('========== 结束==========');
// 
// new Promise(macro task 1)
// ========== 结束==========
// micro task 1
// setTimeout2
// setTimeout1
// 

事件循环机制样例二

注意的点就是await会阻塞下面的代码,等待promise的完成,async函数返回的是一个promise对象

async function f1() {
    
    
      await f2()
      console.log('f1结束')
}
async function f2() {
    
    
    await f3()
    console.log('f2结束')
}
async function f3() {
    
    
    console.log('f3结束')
}
f1()
new Promise(res => {
    
    
    console.log('new Promise')
    res()
}).then(res => {
    
    
    console.log('promise第一个then')
}).then(res => {
    
    
    console.log('promise第二个then')
})
/*
f3结束
new Promise
f2结束
promise第一个then
f1结束
promise第二个then
*/

事件循环机制样例三


console.log('1');

setTimeout(function () {
    
    
    console.log('2');
    Promise.resolve().then(function () {
    
    
        console.log('3');
    })
    new Promise(function (resolve) {
    
    
        console.log('4');
        resolve();
    }).then(function () {
    
    
        console.log('5')
    })
})
Promise.resolve().then(function () {
    
    
    console.log('6');
})
new Promise(function (resolve) {
    
    
    console.log('7');
    resolve();
}).then(function () {
    
    
    console.log('8')
})

setTimeout(function () {
    
    
    console.log('9');
    Promise.resolve().then(function () {
    
    
        console.log('10');
    })
    new Promise(function (resolve) {
    
    
        console.log('11');
        resolve();
    }).then(function () {
    
    
        console.log('12')
    })
})
// 1
// 7
// 6
// 8
// 2
// 4
// 3
// 5
// 9
// 11
// 10
// 12

猜你喜欢

转载自blog.csdn.net/weixin_42100456/article/details/114993710
今日推荐