事件循环:微任务和宏任务在v8中实现的简单理解
微任务
在js中,当使用promise,会将当前任务加入事件执行的微任务队列,有且只有这一种方法可以,因为当使用了promise,在JS引擎中会触发VM::queueMicrotask,会向m_microtaskQueue队列中压入事件,在V8中只有这一种暴露方式,没有其他接口可以调用这个方法
void VM::queueMicrotask(JSGlobalObject& globalObject, Ref<Microtask>&& task)
{
m_microtaskQueue.append(makeUnique<QueuedTask>(*this, &globalObject, WTFMove(task)));
}
然后会执行VM::drainMicrotask,只要m_microtaskQueue不为空就会一直取微任务队列第一个去执行
void VM::drainMicrotasks()
{
do {
while (!m_microtaskQueue.isEmpty()) {
m_microtaskQueue.takeFirst()->run();
if (m_onEachMicrotaskTick)
m_onEachMicrotaskTick(*this);
}
didExhaustMicrotaskQueue();
} while (!m_microtaskQueue.isEmpty());
finalizeSynchronousJSExecution();
}
所以Promise会将事件放到微任务队列的最后一位,然后继续执行,如果promise嵌套,内层的promise也会被放到微任务队列的最末尾,然后执行的时候再将其中的任务放到队列的末尾
宏任务
但是相比于微任务是js-core中自带的基础设施,js-core源代码中是不包含宏任务相关内容的,对于宏任务的相关内容是在C++的js引擎中实现的,单个js代码是通过语句是通过evaluateScript进行执行,而宏任务的实现相当于在C++中通过循环来去执行多个evaluateScript方法,而每个evaluateScript在执行前都有lock保证队列已经清空
下面是宏任务实现的伪代码:
// 初始化JS的执行环境
JSContext* context = [[JSContext alloc] init];
// 初始化C++环境的宏任务队列
NSMutableArray * macroTaskQueue = [[NSMutableArray alloc] init];
// 创建微任务锁
NSConditionLock* condLock = [[NSConditionLock alloc] initWithCondition:0];
// 引入js中的console.log方法,并转换为NSlog输出
context[@"console"] = [JSValue valueWithNewObjectInContext:context];
context[@"console"][@"log"] = ^(JSValue* s) {
NSLog(@"%@", [s toString]);
};
// 引入setTimeout方法
context[@"setTimeout"] = ^(JSValue* f, JSValue* duration) {
NSThread* timer = [[NSThread alloc]initWithBlock:^{
[NSThread sleepForTimeInterval:[duration toDouble] / 1000]; // 休眠1秒
[condLock lock]; // 使用锁
[macroTaskQueue addObject:f]; // 将任务的压入引擎宏任务队列
[condLock unlockWithCondition:1]; 将微任务锁设置为1
//[f callWithArguments:@[]];
}];
[timer start];
};
NSThread* scanner = [[NSThread alloc]initWithBlock:^{
char sourceCode[1024];
while(scanf("%[^\n]", sourceCode) != -1) {
getchar();
[condLock lock];
[macroTaskQueue addObject:[NSString stringWithUTF8String: sourceCode]];
[condLock unlockWithCondition:1];
}
}];
[scanner start];
while(true) { //Event Loop
[condLock lockWhenCondition:1]; // 将锁设置位1
for (id task in macroTaskQueue){
if([task isKindOfClass:JSValue.class])
[task callWithArguments:@[]];
if([task isKindOfClass:NSString.class]) {
JSValue* result = [context evaluateScript:task]; // 执行js内容
NSLog(@"%@", [result toString]);
}
}
[macroTaskQueue removeAllObjects]; // 将宏任务队列清空
[condLock unlockWithCondition:0]; // 将锁设置位0
}
事件循环:微任务和宏任务在v8中实现的简单理解的更多相关文章
- javascript事件环微任务和宏任务队列原理
哈喽!大家好!我是木瓜太香,我又来嘞,今天来说说前端面试中经常别问到的 JS 事件环问题. JS 事件环 JS 程序的运行是离不开事件环机制的,这个机制保证在发生某些事情的时候我们有机会执行一个我们事 ...
- js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)
javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...
- 事件循环 EventLoop(Promise,setTimeOut,async/await执行顺序)
什么是事件循环?想要了解什么是事件循环就要从js的工作原理开始说起: JS主要的特点就是单线程,所谓单线程就是进程中只有一个线程在运行. 为什么JS是单线程的而不是多线程的呢? JS的主要用途就是与用 ...
- 深入理解JavaScript的事件循环(Event Loop)
一.什么是事件循环 JS的代码执行是基于一种事件循环的机制,之所以称作事件循环,MDN给出的解释为 因为它经常被用于类似如下的方式来实现 while (queue.waitForMessage()) ...
- 浅谈 Event loop (事件循环)
从Event Loop谈JS的运行机制 先来理解一个概念: JS分为同步任务和异步任务 同步任务都在主线程上执行,形成一个执行栈 Execute Content Stack 主线程之外,事件触发线程管 ...
- js的事件循环机制和任务队列
上篇讲异步的时候,提到了同步队列和异步队列的说法,其实只是一种形象的称呼,分别代表主线程中的任务和任务队列中的任务,那么此篇我们就来详细探讨这两者. 一.来张图感受一下 如果看完觉得一脸懵逼,请继续往 ...
- JavaScript专题之事件循环
准备知识 1. 进程(process) 进程是系统资源分配一个独立单位,一个程序至少有一个进程.比方说:一个工厂代表一个 CPU, 一个车间就是一个进程,任一时刻,只能有一个进程在运行,其他进程处于非 ...
- 浏览器中的JavaScript事件循环机制
浏览器的事件循环机制是HTML中定义的规范. JavaScript有一个主线程和调用栈,所有的任务都会被放到调用栈等待主线程执行. JS调用栈 是一种先进后出的数据结构.当函数被调用时,会被添加到栈中 ...
- JS浏览器事件循环机制
文章来自我的 github 博客,包括技术输出和学习笔记,欢迎star. 先来明白些概念性内容. 进程.线程 进程是系统分配的独立资源,是 CPU 资源分配的基本单位,进程是由一个或者多个线程组成的. ...
随机推荐
- Java 集合常见知识点&面试题总结(上),2022 最新版!
你好,我是 Guide.秋招即将到来(提前批已经开始),我对 JavaGuide 的内容进行了重构完善,公众号同步一下最新更新,希望能够帮助你. 你也可以在网站(javaguide.cn)上在线阅读, ...
- NC207028 第k小数
NC207028 第k小数 题目 题目描述 给你一个长度为 \(n\) 的序列,求序列中第 \(k\) 小数的多少. 输入描述 多组输入,第一行读入一个整数 \(T\) 表示有 \(T\) 组数据. ...
- kubectl 最新常用命令 --V1.24版本
Kubectl 自动补全 BASH source <(kubectl completion bash) # 在 bash 中设置当前 shell 的自动补全,要先安装 bash-completi ...
- .Net之延迟队列
介绍 具有队列的特性,再给它附加一个延迟消费队列消息的功能,也就是说可以指定队列中的消息在哪个时间点被消费. 使用场景 延时队列在项目中的应用还是比较多的,尤其像电商类平台: 订单成功后,在30分钟内 ...
- 【Nim 游戏】 学习笔记
前言 没脑子选手随便一道博弈论都不会 -- 正文 Nim 游戏引入 这里给出最简单的 \(Nim\) 游戏的题目描述: \(Nim\) 游戏 有两个顶尖聪明的人在玩游戏,游戏规则是这样的: 有\(n\ ...
- 【docker专栏3】docker基础概念-容器、镜像以及引擎组成部分
一.docker镜像与容器 docker镜像是一个可执行的静态独立软件包,包含打包程序代码和软件运行环境等文件.如:代码.运行时库.环境变量和配置文件等都包含在其中.容器是镜像的运行时状态(镜像中的软 ...
- Deep Learning-深度学习(一)
深度学习入门 1.人工智能.机器学习.深度学习 1.1 人工智能(AI) 一个比较宽泛的概念.即用来模拟人的智能的理论,并对这个模拟出来的智能进行延伸和开拓.通俗来讲就是要达到用机器模拟人类的聪慧来处 ...
- Docker安装NextCloud使用MySQL
安装 1.拉取并启动MySQL,最好把数据可目录挂载到宿主机,以便容器被误删后恢复: docker run --name=nextcloud_db \ -e MYSQL_ROOT_PASSWORD=X ...
- YYYYMMdd和yyyyMMdd的区别
YYYYMMdd的 YYYY 是表示:当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,那么这周就算入下一年.比如今天是2021-12-29 星期三,然后本周六是2022-01-01,存 ...
- Windows高效开发环境配置(一)
更多精彩内容,欢迎关注公众号:逻魔代码 前言 用了多年的 MacOS 做开发,一系列诸如 Alfred.Item2.Oh-my-zsh 之类的工具,大大地提升了工作的效率和使用舒适度.新工作不给配 M ...