事件循环:微任务和宏任务在v8中实现的简单理解

  • 事件循环:微任务和宏任务在v8中实现的简单理解已关闭评论
  • 164 次浏览
  • A+
所属分类:Web前端
摘要

在js中,当使用promise,会将当前任务加入事件执行的微任务队列,有且只有这一种方法可以,因为当使用了promise,在JS引擎中会触发VM::queueMicrotask,会向m_microtaskQueue队列中压入事件,在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(@"%@", 展开); };  // 引入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 }