微任務 在js中,當使用promise,會將當前任務加入事件執行的微任務隊列,有且只有這一種方法可以,因為當使用了promise,在JS引擎中會觸發VM::queueMicrotask,會向m_microtaskQueue隊列中壓入事件,在V8中只有這一種暴露方式,沒有其他介面可以調用這個方法 vo ...
微任務
在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
}