nodejs event loop

任务注册

setupTaskQueue

{nextTick, runNextTicks} internal/process/task_queues 暴露两个方法给nodejs的process用

// MARK: nodejs自己用js实现的一个 队列, 用来存放nextTick回调函数
const queue = new FixedQueue();

// ...
// 插入nextTick回调函数
function nextTick(callback) {
	// 先设置标识 为 true: 表示需要忘 c++ 中的tak_queue中的tickInfo[0] 首位插入 1 
	if (queue.isEmpty()) setHasTickScheduled(true);
	// 生成异步ID
	const asyncId = newAsyncId();
	// 任务触发ID
	const triggerAsyncId = getDefaultTriggerAsyncId();
	// tick
	const tickObject = {
	  [async_id_symbol]: asyncId,
	  [trigger_async_id_symbol]: triggerAsyncId,
	  callback,
	  args
	};
	// 初始化成功
	if (initHooksExist())
	// 发出事件
	  emitInit(asyncId, 'TickObject', triggerAsyncId, tickObject);
	// 队列中添加
	queue.push(tickObject);
}

// 运行nextTick
function runNextTicks() {
	// 如果没有 nextTick 或者 promiseRejection 则只运行 runMicrotasks 函数, 否则运行 processTicksAndRejections 函数。
  if (!hasTickScheduled() && !hasRejectionToWarn())
    runMicrotasks();
  if (!hasTickScheduled() && !hasRejectionToWarn())
    return;

  processTicksAndRejections();
}

// 真的运行nextTick
function processTicksAndRejections() {
	// 如果queue中有nextTick, 就将queque中的callback一个一个地拿出来运行
	// 最后清空 相关字段
	if (destroyHooksExist()) emitDestroy(asyncId);
	// 运行结束后的钩子
	emitAfter(asyncId);
	// 如果有promise.then和reject的微任务(processPromiseRejections),
	runMicrotasks();
	
	// 最后,将微任务列表状态设置为 false
	setHasTickScheduled(false);
  	setHasRejectionToWarn(false);
}

getTimerCallbacks

internal/timers

// 启动的时候在lib/internal/timers中创建单链:
const immediateQueue = new ImmediateList();
// 创建一个堆,根据时间和创建先后排序
// PriorityQueue——一个高效的二进制堆实现,在最坏情况下执行所有操作的时间为O(log n)
const timerListQueue = new PriorityQueue(compareTimersLists, setPosition);
// 用来缓存,timer数据
// key = 毫秒级的时间  value为链表
const timerListMap = ObjectCreate(null);

// 暴露的方法会执行nextTicks列表以及微任务 (闭包)
function getTimerCallbacks(runNextTicks) {
	// processImmediate的逻辑就是逐个执行immediate任务队列的节点。Immediate分两个队列,正常情况下,插入的immediate节点插入到immediateQueue队列
	// 如果执行的时候有异常,则未处理完的节点就会被插入到outstandingQueue队列,等下一次循环时先执行
	function processImmediate() {
		const queue = outstandingQueue.head !== null ?
      outstandingQueue : immediateQueue;
		const immediate = queue.head


		let prevImmediate;
    	let ranAtLeastOneImmediate = false;
		// 开始逐个执行任务 先执行一个_onImmediate,而后每次循环前,先执行 微任务和 nextTick
		while(immediate !== null) {
			// 执行微任务队列
			if (ranAtLeastOneImmediate) runNextTicks();
	      	else ranAtLeastOneImmediate = true;

			
			if (immediate._destroyed) {
		        outstandingQueue.head = immediate = prevImmediate._idleNext;
		        continue;
		     }

			// 执行下一个节点
			outstandingQueue.head = immediate = immediate._idleNext;
		}
	}

	// 处理计时器
	function processTimers(now) {
		let list;
   		let ranAtLeastOneList = false;
   		// 逐个处理已经过期的计时器任务,以及每次循环前,先执行nextTicks和v8微任务
   		while(list = timerListQueue.peek()) {
			if (list.expiry > now) {
		        nextExpiry = list.expiry;
		        return refCount > 0 ? nextExpiry : -nextExpiry;
		      }
		    // 第二次循环往后,执行微任务
		    if (ranAtLeastOneList) runNextTicks();
      		else ranAtLeastOneList = true;
      		listOnTimeout(list, now);
		}
		return 0;
	}

	function listOnTimeout(list, now) {
	
		while (timer = L.peek(list)) {
			if (ranAtLeastOneTimer) runNextTicks();
	      	else ranAtLeastOneTimer = true;
	
			// 当超时,移除任务
			L.remove(timer);

			// 如果是setInterval
			if (timer._repeat) start = getLibuvNow();
			
			// 先执行当前timer
			timer._onTimeout()

			// 如果是setInterval这种repeat任务,需要重新insert, 否则结束
			timer._idleTimeout = timer._repeat;

			// 所有定时器缓存在timerListMap中,每个迭代时间都有一个列表,每个时间间隔区间的任务存储在一个单独的list,如果没有就需要单独创建, 所有这个任务链表放在一个mini heap结构中
			// timer._idleTimeout,会被截断,保证亚毫秒级的准确性
			// 如:msecs = MathTrunc(msecs);
          	insert(timer, timer._idleTimeout, start);
          	
			// 否则结束
			timer._destroyed = true;
		}
	}

	return {
	  processImmediate,
	  processTimers
	};
}

lib/internal/bootstrap/node.js

 const { processImmediate, processTimers } = getTimerCallbacks(runNextTicks);
 const { setupTimers } = internalBinding('timers');
 setupTimers(processImmediate, processTimers);

setupTimers

src/timers.cc

void SetupTimers(const FunctionCallbackInfo<Value>& args) {
  CHECK(args[0]->IsFunction());
  CHECK(args[1]->IsFunction());
  auto env = Environment::GetCurrent(args);

  // 在nodejs启动的时候就将各个任务注册到nodejs
  env->set_immediate_callback_function(args[0].As<Function>());
  env->set_timers_callback_function(args[1].As<Function>());
}

env.h
定义了一个带参宏V,而这个宏在调用的时候会定义一个属性,所以在通过V(immediate_callback_function, v8::Function) 调用后,可以实现env->set_immediate_callback_function的调用了,同时还会生成一个成员函数PropertyName(),所以在调用后同时也会使得env->immediate_callback_function成为可调用函数。
args[0]在这里指的便是processImmediate,所以通过SetupTimers可以使processImmediate这个函数最终注册到node中。

V(immediate_callback_function, v8::Function)   

#define V(TypeName, PropertyName)                                           
  inline v8::Local<TypeName> PropertyName() const;
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
  PER_ISOLATE_STRING_PROPERTIES(VS)
#undef V

新增/删除异步任务

lib/timers.js

setImmediate / clearImmediate

setImmediate会新建一个节点,并把节点append到immediateQueue,并返回当前节点
clearImmediate会从immediateQueue删除指定的节点

function setImmediate() {
	// ...
	return new Immediate(callback, args);
}

function clearImmediate(immediate) {
	// ...
	immediateQueue.remove(immediate);
}

setTimeout / clearTimeout

setTimeout会新建一个timeout节点,然后执行insert,在insert操作中,会先判断timerListMap是否有该msecs毫米级的链表,有就append,没有就先创建TimersList,然后append,在存入堆:timerListQueue
clearTimeout执行删除操作,删除msecs级别的任务,然后看该链表是否已空,空就在timerListQueue和timerListMap中删除

function setTimeout() {
	// ...
	const timeout = new Timeout(callback, after, args, false, true);
	
  	insert(timeout, timeout._idleTimeout);
}

function clearTimeout(timer) {
	// ...
	unenroll(immediate);
}

setInterval / clearInterval

setInterval会先按照setImmediate的方式,插入repeat属性的节点,然后在event loop时,会检查该属性,然后再新建一个任务,insert到指定的链表中
clearInterval删除节点,基本同clearTimeout

function setInterval() {
	// ...
	const timeout = new Timeout(callback, repeat, args, false, true);
	
  	insert(timeout, timeout._idleTimeout);
}

function clearInterval(immediate) {
	// ...
	unenroll(immediate);
}

任务执行

src/env.cc

InitializeLibuv


// TODO:
uv_check_start(immediate_check_handle(), CheckImmediate);

// 这里执行的是uv的官方的⌚️
uv_async_init(
      event_loop(),
      // task_queues_async_用于子线程和主线程通信
      &task_queues_async_,
      // uv_async_cb
      [](uv_async_t* async) {
        Environment* env = ContainerOf( &Environment::task_queues_async_, async);
        env->RunAndClearNativeImmediates();
      }
    );

CheckImmediate

src/env.cc


 do {
 // MakeCallback来自src/api/callbacl.cc
    MakeCallback(env->isolate(),
                 env->process_object(),
                 env->immediate_callback_function(),
                 0,
                 nullptr,
                 {0, 0}).ToLocalChecked();
  } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值