【javascript】异步-事件轮询-任务队列-工作队列(job queque)

异步

异步编程的核心: 现在 与 稍后 的部分之间的关系。
例子: 去吃饭排队,先拿一个号,排到了手机会有消息收到。在这个时候,可以取买点喝的。

现在:排队拿号 -> 买水 。
稍后:短信通知排到了,开吃!

event loop 事件轮询

我们将事件轮询理解成一个永动机,它一直会去找某一个队列【就可以理解成一个数组】里面的是否有执行的任务,如果有,那么会去执行。

模拟代码:

	var eventLoop = [];
	var event;
	// 永远执行
	while (true) {
	    // 检查队列是否有数据
	    // 执行一个tick
		if (eventLoop.length > 0) {
			event = eventLoop.shift();
			try {
				event();
			} 
			catch(err) {
				reportError(err); // report Error stack info 
			}
			
		}
	}

js引擎 遇到异步代码块,会将它放到【不一定是马上】任务队列里面,当主线程执行完所有代码的时候,会从这个任务队列里面取任务,如果有就执行。

setTimeout 不会将回调放在事件轮询队列上,定时器超时的时候,环境才会把你的回调放进事件轮询,这样在未来的tick中将会被取出执行。


虽说js是单线程,但是在事件轮询 和 并发模型机制上,并非是单线程。 除了主线程callstack , 还有一个专门处理回调函数或者事件的线程(在浏览器里面就是webAPI,node里面就是线程 )。外面有一个task queue,这里就是回调等待的地方。

比如遇到了A , A 有一个回调,A函数执行了,A的回调放到了 另外的线程,另外的线程在满足一定条件(可能是setTimeout 或者response响应)之后就会将这个回调放到 task queue 里面, callstack [必须]clear之后会马上去task queue 里面一个一个执行这个队列的代码,执行完一个,task queue的这个就回收。

cool video: https://www.youtube.com/watch?v=8aGhZQkoFbQ
在这里插入图片描述

[大白话]: 主线程的代码执行完毕之后,然后会去task queue(任务队列)去执行队列中的任务。

所以

	console.log("one")
	setTimeout(()=>{
		console.log("two")
	}, 0)
	console.log("three")

结果会是:

	"one"
	"three"
	"two"

而不是one two three

但是ES6 引入了promise generator async 等异步概念,他们是不是也是被放到了task queque呢。。答案是否定的。

在任意特定的时刻,一次只有一个队列中的一个事件可以被处理,当事件执行的时候,它可以间接的或者直接的引发(导致)一个或者更多的后续事件。

一个task queue 引发了后续的task queue的例子

(function () {
  console.log('main stack')
  setTimeout(() => {
    console.log("1 in task queue one")
    setTimeout(() => {
      console.log("11 in task queue two")
    }, 0)
  }, 0)

 setTimeout(() => {
    console.log("2 in task queue one")
    setTimeout(() => {
      console.log("22 in task queue two")
    }, 0)
  }, 0)
})()



es6引入了新的概念:job queque(工作队列), Promise的异步行为是基于job的。
实际上这个概念,就是和微任务队列microqueue是类似的。


宏观任务队列、微观任务队列

常见的macro-task宏观任务有: setTimeout 、 setInterval、script、I/O操作、UI渲染
常见的micro-task微观任务有:promise的then回调函数、async函数里面await表达式后面的代码。

上面我们知道了 setTimeout 的回调函数,必须等待callstack主线程的同步代码执行完毕之后,才去执行,这一步已经理解了,主线程也是第一个宏任务。

但是我们看下面的代码:

console.log('script start');

setTimeout(function() {
  console.log('setTimeout');
}, 0);

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('script end');

执行结果是

script start
script end
promise1
promise2
setTimeout

promise的构造函数为同步代码,then回调函数会被放到微任务队列里面。
settimeout的回调函数会被放到task queue 宏任务队列里面。

callstack 主线程的同步代码[第一个宏任务]执行完毕---->> 微任务队列 ----> 第二个宏任务 settimeout —>>微任务队列

宏任务是执行的基本单元,微任务队列是从属于一个宏任务的。


还有一种情况是async 函数:

async函数表示函数里面可能会有异步方法,await后面跟一个表达式,async方法执行时,遇到await会立即执行表达式,然后把表达式后面的代码放到微任务队列里,让出执行栈让同步代码先执行。

如果后面的代码有return 语句,比如return xxx,会立即返回一个promise:Promise.resolve( xxx ),如果没有显示的声明return语句,那么返回的是
Promise.resolve(undefined) , 返回的promise对象会等待await表达式完成之后,才会从pending -> resolved 或者 rejected


小测试

下面这段代码的打印结果是啥呢?

	async function async1() {
	  console.log('async1 start')
	  await async2()
	  console.log('async1 end')
	}
	async function async2() {
	  console.log('async2')
	}
	
	
	console.log('script start')
	setTimeout(function () {
	  console.log('settimeout')
	})
	async1()
	new Promise(function (resolve) {
	  console.log('promise1')
	  resolve()
	}).then(function () {
	  console.log('promise2')
	})
	console.log('script end')

还有这个呢?

   setTimeout(()=>{
      console.log('timer1')
      Promise.resolve().then(function() {
        console.log('promise1')
      }).then(function(){
        console.log('promise11')
      })
    }, 0)
    setTimeout(()=>{
        console.log('timer2')
        Promise.resolve().then(function() {
          console.log('promise2')
        }).then(function(){
          console.log('promise22')
        })
    }, 0)

参考:
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/33
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
《you dont know javascript》第五章 异步与性能

补充-- 2020 09-28

requestAnimationFrame 是属于宏任务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值