前端面试题汇总(算法篇二)--promise和setTimeout的输出顺序

宏任务与微任务的执行顺序

同步任务和异步任务
JavaScript是单线程执行的语言,在同一个时间只能做一件事情。这就导致后面的任务需要等到前面的任务完成才能执行,如果前面的任务很耗时就会造成后面的任务一直等待。为了解决这个问题JS中出现了同步任务和异步任务。

(1)同步任务
在主线程上排队执行的任务只有前一个任务执行完毕,才能执行后一个任务,形成一个执行栈。

(2)异步任务
不进入主线程,而是进入任务队列,当主线程中的任务执行完毕,就从任务队列中取出任务放进主线程中来进行执行。由于主线程不断重复的获得任务、执行任务、再获取再执行,所以者种机制被叫做事件循环(Event Loop)

执行顺序示例

 1、new promise事件只要建立,里面的代码会立即执行;
2、promise.then()和process.nextTick()的代码会在本轮"事件循环"结束时执行;
3、setTimeoutd(fn, 0)的代码会在下一轮"事件循环"开始时执行;
4、最后执行setTimeout(fn,1000)的代码。

setTimeout(function () {
	var np =new  Promise(function (resolve,reject) {
		console.log(1)
		resolve()
	})
	np.then(_=>{
		console.log(2)
	})
	console.log(3)
},1000)
 
var pro = new Promise((resolve, reject) => {
	console.log(5)
	resolve()
}).then(_=>{
	setTimeout(function () {
		console.log(6)
	},0)
	return 7;
}).then(n=>{
	console.log(n)
})
console.log(4)
//执行结果 5  4  7  6  1  3  2

js会先执行 同步任务 例如题中的console.log()再执行new Promise中的console.log(),再寻找
异步任务中的微任务 promise.resolve.then(),最后寻找 异步任务中的宏任务 setTimeout(),最后执行结束。

// 整体script作为第一个宏任务进入主线程......0
      // 同步任务console.log直接执行
      console.log('1'); ......1
      async function first() {
        console.log('first函数'); ......3
      }
      // 宏任务最后执行
      setTimeout(() => {
        console.log('settimeout  2'); .......7
      }, 0);
      // .then微任务
      Promise.resolve().then(() => {
        console.log('promise  3'); ......5
      });
      // 遇到new Promise直接执行,遇到.then分配到微任务队列中
      new Promise((resolve, reject) => {
        // new Promise里面的输出直接执行
        console.log(4); ......2
        // resolve暂停跳出Promise
        resolve();
      }).then((res) => {
        console.log(5); ......6
      });
      // 调用first函数,输出
      first();
      // 同步任务直接输出
      console.log('6'); ......4
//输出顺序   1     4     first函数    6    promise 3    5   settimeout 2

 await和resolve会暂停当前promise直到别的异步任务结束才继续执行。例如题中的new Promise
resolve后不继续向下执行,而是寻找其他同步任务,同步任务全部结束,寻找异步任务中的微任务,最后在执行new Promise .then的微任务,最后再寻找异步任务中的宏任务执行。

console.log(1);

async function asyFunction () {
    console.log(2);
    await console.log(3);
    await console.log(4);
    console.log(5);
    return 6
}

new Promise((resolve, reject) => {
    console.log(10);
    resolve();
}).then(res => {
    console.log(11);
})

console.log(7);

setTimeout(() => {
    console.log(8)
}, 0)

setTimeout(() => {
    console.log(9)
}, 1000)

asyFunction().then(res => { console.log(res) });
//输出结果  1 10 7 2 3 11 4 5 6 8 9

依次看代码,未执行的先别看, Promise.resolve().then(() ...微任务,放进堆中;setTimeout宏任务放进堆中,执行async1,回去看async1,输出1;await会隐式的生成promise,将后面的代码放进promise.then中,并执行本身,所以输出2,将3放进堆中;接着往下执行,输出6;3和4都为then,看代码执行顺序,所以是4,3;最后是宏任务5

async function async1 () {
  console.log(1);
  const result = await async2();
  console.log(3);
}
async function async2 () {
  console.log(2);
}
Promise.resolve().then(() => {
  console.log(4);
});
setTimeout(() => {
  console.log(5);
});
async1();
console.log(6);
//结果 1  2  6  4   3   5

 setTimeout宏任务放进堆中,test未执行先别看;进入Promise输出2,遇到回调函数(微任务)放进堆中,往下走async2未执行继续往下走,执行test输出5,await紧跟的函数立即执行,隐式生成一个promise,后面的代码包裹在promise.then中成为微任务放进堆中,执行完test继续往下走,输出4,执行完代码回到堆中执行微任务,微任务根据代码的执行顺序依次执行,then的优先级大于finally(finally和async创建的.then属于第一次回调一个层级的
,finally后面的.then已经是第二次回调了所以放在下一级微任务里了)所以先输出3,6再输出8,执行完微任务执行宏任务

setTimeout(function () {
  console.log('1');
});
async function test () {
  console.log('5')
  //隐式创建一个微任务 promise.then()
  await async2();
  console.log('6')
}
new Promise(function (resolve) {
  console.log('2');
  resolve();
}).then(function () {
  console.log('3');
}).finally(() => {
  console.log('8');
})
function async2 () {
  console.log('7');
}
test()
console.log('4');
//结果:2、5、7、4、3、6、8、1

猜你喜欢

转载自blog.csdn.net/Holly31/article/details/130778837