同步异步线程理解

568 阅读3分钟

js是单线程语言,所以对在单线程中是如何实现异步操作的一直很好奇,之前读过一篇文章,感觉很好,作为读书笔记记录理解一下。

setTimeout真的保险么?

首先看一个例子:

setTimeout(()=>{
	console.log(0)
 },1000)
sleep(10000)
//十秒过后才会打印0
setTimeout(()=>{
	console.log(0)
 },1000)
 // 一秒过后打印0

在这个例子中,js执行之后,并没有在一秒之后打印0,而是沉睡了10秒之后打印。当然sleep函数要是真正意义上需要执行10秒的函数,而不是setTimeout实现的,否则还是没办法实现上面的效果。

产生上面的情况的原因就是setTimeout这些全局函数是web API的一部分而不是js的一部分.js栈是先进先出的,当js向下执行碰到setTimeout的时候,会将其放进web API中,等待设定时间到了之后,就会将其回调函数放进事件队列中。事件循环(Event Loop)不断监视js调用栈,一旦栈为空,就会将事件队列中的事件放进栈中执行。

第一个例子中,setTimeout的回调函数在一秒后被放入事件队列,但是这时候碰到了sleep,他将占用js调用栈长达十秒,这时候回调函数只能等待,所以十秒后才打印结果。所以上面两个例子表现不同的原因是,setTimeout和setInterval这两个事件的执行原理都大致相同,setInterval规定时间仅仅是定义了每隔多久回调函数从web API中放入时间队列,什么时候执行还要看队列前面的函数的执行时间。

理解了上面事件执行顺序,再来看下浏览器是如何处理事件顺序的。

宏任务和微任务

宏任务(macro task):包括js代码,setTimeout和setInterval;
微任务(macro task):包括Promise,process.nextTick(ps:nodejs);

先看一个例子,试着对每次打印出的东西做出判断:

	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', '2','4', '3','5', '9','11', '10','12';

为了理解上面的输出,我们需要理解的两句话是:宏任务先于微任务执行;并且分块执行。

所以首先执行js主线的‘1’和‘7’(注意: Promise的主函数是宏任务,并且随着js主线顺序执行); 然后执行js主线的微任务输出‘6’和‘8’;
第一个setTimeout被放入webAPI后,然后放在了事件队列里,排在了主线后面,所以接下来执行这里的宏任务打印‘2’和‘4’;
接着这一组里面还包括微任务,也要执行,输出‘3’和‘5’;
第二组的setTimeout后于前一个被放入事件队列,等前面的宏任务和微任务被执行完才开始执行,所以依次输出‘9’‘11’‘10’‘12’;

这样就比较好理解浏览器是怎样处理宏任务和微任务的。

生活的一部分是工作,工作的一部分是解决问题取悦生活,所以好好生活,好好工作,好好热爱(●ˇ∀ˇ●)