- A+
所属分类:Web前端
微任务
在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 }