关于JS任务的划分以及执行顺序

127 阅读2分钟

由于JS任务是单线程执行的,即同一时间只能完成一项任务,后面的任务只有等前面的任务完成才能进行,如果前面的任务很耗时会导致后面的任务无法进行,影响总体的进程

为了解决该问题,防止主线程阻塞,因此出现了同步任务和异步任务

同步任务

在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务,形成一个执行栈。为非耗时任务

异步任务

耗时任务进入任务队列,当主线程中的任务执行完毕,就从任务队列中取出任务放进主线程中来进行执行。

由于主线程不断重复的获取任务、执行任务、再获取再执行,所以这种机制被叫做事件循环。

异步任务又分为宏任务和微任务

宏任务(macrotask)

是由宿主(浏览器发起的)

微任务(microtask)

是由JS自身发起的

image.png  

JS任务执行顺序

先执行主线程任务,当主线程存在微任务时先执行微任务,微任务执行完后开始执行宏任务,一个宏任务执行完后,检查是否有微任务,有微任务则先执行微任务执行完毕后再执行宏任务。如果一个宏任务中包含宏任务,则将所包含的宏任务加入任务队列等待执行。

image.png

 

测试实例

 

实例一

宏任务中包含宏任务

setTimeout(() => {
  console.log(' 1--start');
  setTimeout(() => {
    console.log('2--macrotask')
  }, 0)
  new Promise(resolve => {
    resolve()
    console.log('3--new promise')
  }).then(() => {
    console.log('4--promise then')
  })
}, 0)
 
setTimeout(() => {
  console.log('5--macrotask')
}, 0)
console.log('6--end')


//执行顺序613452 

 

实例二

async await 

注意:Promise是异步的,但是new Promise在实例化的过程中所执行的代码都是同步的,.then中的回调是异步的

async await的底层是基于Promise进行的封装,因此async相当于new Promise的实例化过程,是同步的,而await相当于new Promise中的.then回调,是异步的

async function async1() {
   console.log('1--async1 start');
   await async2();
   console.log('2--async1 end');
}
async function async2() {
   console.log('3--async2');
}


 console.log('4--script start');
   
setTimeout(function() {
   console.log('5--setTimeout');
}, 0)
   
async1();
   
new Promise(function(resolve) {
    console.log('6--promise1');
    resolve();
}).then(function() {
    console.log('7--promise2');
});
console.log('8--script end');


//执行顺序 41368275

注意:Promise是异步的,但是new Promise在实例化的过程中所执行的代码都是同步的,.then中的回调是异步的

async await的底层是基于Promise进行的封装,因此async相当于new Promise的实例化过程,是同步的,而await相当于new Promise中的.then回调,是异步的

实例三 

const bar = () => console.log('1--bar')


const baz = () => console.log('2--baz')


const foo = () => {
  console.log('3--foo')
  
  setTimeout(bar, 0)
  
  new Promise((resolve, reject) =>
    resolve('4--应该在 baz 之后、bar 之前')
    ).then(resolve => console.log(resolve))
    
    baz()
}


//执行顺序 3241

实例四

多个script标签

<script>
  console.log(1);

  setTimeout(() => {
    console.log(5);
  });

  new Promise((resolve) => {
    resolve();
  }).then(() => {
    console.log(3);
  });
  console.log(2);
</script>

<script>
  console.log(4);
</script>

//执行顺序 12345

script标签本身是作为宏任务来存在的