Javascript的循环机制

2021-07-05  本文已影响0人  捡了幸福的猪

总结:

  • 浏览器是多进程的; 其中一个进程是浏览器渲染进程
  • 浏览器渲染进程包括多个线程; 其中一个线程是 JS引擎线程(负责解析和执行Javascript脚本);其他线程是 GUI渲染线程、事件触发线程、定时器触发线程、异步http请求线程。
  • 常说的主线程是指: JS引擎线程;
  • JS 是单线程是指: JS引擎线程只有1个;
  • 执行顺序:先执行宏任务中同步任务,再执行其对应微任务

下面进行分析:

进程 & 线程

比喻:进程比作工厂,内存比作每个工厂拥有的资源,线程比作工厂里的工人。每个工厂中会有一个或者若干个工人来协作完成某个任务。每个工厂相互独立,但同一个工厂之间的工人共享资源。

通常所说的单线程和多线程,其中的“单”和“多”,一般指的是一个进程里有一个单线程或有多个线程。

执行规则

1、基本规则

setTimeout(() => {
  console.log('2秒到了')
}, 2000)

分析: setTimeout是异步操作首先进入event table,注册的事件就是他的回调,触发条件就是2秒之后,当满足条件回调被推入event queue,当主线程空闲时会去event queue里查看是否有可执行的任务。

2、细化规则: 宏任务&微任务
宏任务(macro-task):包括整体代码script、setTimeout、setInterval、MessageChannel、postMessage、setImmediate。
微任务(micro-task):Promise、process.nextTick、MutationObsever。

setTimeout(function() {
    console.log('4')
})

new Promise(function(resolve) {
    console.log('1') // 同步任务
    resolve()
}).then(function() {
    console.log('3')
})
console.log('2')

分析:

第一轮事件循环结束了,我们开始第二轮循环。

-从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。

栗子2:

console.log('1')
setTimeout(function() {
    console.log('2')
    process.nextTick(function() {
        console.log('3')
    })
    new Promise(function(resolve) {
        console.log('4')
        resolve()
    }).then(function() {
        console.log('5')
    })
})

process.nextTick(function() {
    console.log('6')
})

new Promise(function(resolve) {
    console.log('7')
    resolve()
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9')
    process.nextTick(function() {
        console.log('10')
    })
    new Promise(function(resolve) {
        console.log('11')
        resolve()
    }).then(function() {
        console.log('12')
    })
})

第一轮事件循环正式结束,这一轮的结果是输出1,7,6,8。那么第二轮事件循环从setTimeout1宏任务开始:

第二轮事件循环结束,第二轮输出2,4,3,5。第三轮事件循环从setTimeout2宏任务开始:

第三轮事件循环结束,第三轮输出9,11,10,12。

console.log('1')   // 宏任务1
setTimeout(function() {
    console.log('2')    // 宏任务2
    process.nextTick(function() {
        console.log('3')  // 宏任务2-微任务1
    })
    new Promise(function(resolve) {
        console.log('4')  // 宏任务2
        resolve()
    }).then(function() {
        console.log('5')   // 宏任务2-微任务2
    })
})

process.nextTick(function() {
    console.log('6') // 宏任务1-微任务1
})

new Promise(function(resolve) {
    console.log('7')  // 宏任务1
    resolve()
}).then(function() {
    console.log('8')  // 宏任务1-微任务2
})

setTimeout(function() {
    console.log('9')   // 宏任务3
    process.nextTick(function() {
        console.log('10')  // 宏任务3-微任务1
    })
    new Promise(function(resolve) {
        console.log('11') // 宏任务3
        resolve()
    }).then(function() {
        console.log('12')  // 宏任务3-微任务2
    })
})

栗子3:

new Promise(function (resolve) { 
    console.log('1')// 宏任务一
    resolve()
}).then(function () {
    console.log('3') // 宏任务一的微任务
})
setTimeout(function () { // 宏任务二
    console.log('4')
    setTimeout(function () { // 宏任务五
        console.log('7')
        new Promise(function (resolve) {
            console.log('8')
            resolve()
        }).then(function () {
            console.log('10')
            setTimeout(function () {  // 宏任务七
                console.log('12')
            })
        })
        console.log('9')
    })
})
setTimeout(function () { // 宏任务三
    console.log('5')
})
setTimeout(function () {  // 宏任务四
    console.log('6')
    setTimeout(function () { // 宏任务六
        console.log('11')
    })
})
console.log('2') // 宏任务一

结果: 1、2、3、4、5、6、7、8、9、10、11、12

3、结合async/await 执行规则

    async function func () {
     const res1 = await new Promise((resolve) => {
       setTimeout(()=>resolve('promise1'), 1000);
     });
     const res2 = await new Promise((resolve) => {
        setTimeout(()=>resolve('promise2'), 1000);
      });
      return [res1, res2]
    }
    func().then(console.log)   // ["promise1", "promise2"]
//  js 实现休眠
    function sleep(interval) {
      return new Promise(resolve => {
        setTimeout(resolve, interval);
      })
    }

    async function sleepUse() {
      for(let i = 1; i <= 5; i++) {
        console.log(i);
        await sleep(1000);
      }
    }
    sleepUse();

上面是关于async/await 的基础知识。 结合async/await 的事件规则 就是: 将async/await 转化为promise理解。

🌰1:

setTimeout(function () {
  console.log('6')
}, 0)
console.log('1')
async function async1() {
  console.log('2')
  await async2()
  console.log('5')
}
async function async2() {
  console.log('3')
}
async1()
console.log('4')

结果: 1 2 3 4 5

栗子2:

console.log('1')   // 宏任务1
async function async1() {
  console.log('2')  // 宏任务1
  await 'await的结果' 
  console.log('5')   // 宏任务1-微任务1
}

async1()  // 宏任务1
console.log('3')   // 宏任务1

new Promise(function (resolve) {
  console.log('4')  // 宏任务1
  resolve()
}).then(function () {
  console.log('6')  // 宏任务1-微任务2
})

🌰3:

async function async1() {
  console.log('2')   // 宏任务1
  await async2()
  console.log('7')  // 宏任务1 - 微任务1
}

async function async2() {
  console.log('3')    // 宏任务1
}

setTimeout(function () {
  console.log('8')   // 宏任务2
}, 0)

console.log('1')  // 宏任务1
async1()

new Promise(function (resolve) {
  console.log('4')   // 宏任务1
  resolve()
}).then(function () {
  console.log('6') // 宏任务1-微任务2
})
console.log('5') // 宏任务1

结果: 1 -> 2 -> 3 -> 4 -> 5 -> 7 -> 6 -> 8

🌰4:

setTimeout(function () {
  console.log('9')
}, 0)  // 宏任务2
console.log('1')   // 宏任务1
async function async1() {
  console.log('2')   // 宏任务1
  await async2()
  console.log('8')   // 宏任务1-微任务3
}
async function async2() {
  return new Promise(function (resolve) {
    console.log('3')   // 宏任务1
    resolve()
  }).then(function () {
    console.log('6')  // 宏任务1-微任务1
  })
}
async1()

new Promise(function (resolve) {
  console.log('4')   // 宏任务1
  resolve()
}).then(function () {
  console.log('7') // 宏任务1-微任务2
})
console.log('5') // 宏任务1

栗子:

async function async1() {
  console.log('2')   // 宏任务1
  const data = await async2()
  console.log(data)   // await的结果
  console.log('8')  // 宏任务1-微任务3
}

async function async2() {
  return new Promise(function (resolve) {
    console.log('3')   // 宏任务1
    resolve('await的结果')
  }).then(function (data) {
    console.log('6')    // 宏任务1-微任务1
    return data
  })
}
console.log('1')  // 宏任务1

setTimeout(function () {
  console.log('9')
}, 0)  // 宏任务2

async1()

new Promise(function (resolve) {
  console.log('4')    // 宏任务1
  resolve()
}).then(function () {
  console.log('7')  // 宏任务1-微任务2
})
console.log('5')    // 宏任务1

🌰:

const async1 = async () => {
  console.log('async1');
  setTimeout(() => {
    console.log('timer1')
  }, 2000)
  await new Promise(resolve => {
    console.log('promise1')
  })
  console.log('async1 end')
  return 'async1 success'
} 
console.log('script start');
async1().then(res => console.log(res));
console.log('script end');
Promise.resolve(1)
  .then(2)
  .then(Promise.resolve(3))
  .catch(4)
  .then(res => console.log(res))
setTimeout(() => {
  console.log('timer2')
}, 1000)

此例子需要注意的点是:

备注:本文总结自「从event loop到async await来了解事件循环机制」原文链接为https://juejin.cn/post/6844903740667854861

hi ~ 你好鸭~

上一篇 下一篇

猜你喜欢

热点阅读