iOS JavaScriptCore 笔记一 — 初识

参考文章

  • Nate Cook撰写、 April Peng翻译、 发布于2015年1月19日
  • JavaScriptCore全面解析 (上篇)
  • JavaScriptCore全面解析 (下篇)

概述

几个重要的类

#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"

iOS JavaScriptCore 笔记一 — 初识_第1张图片
示意图一

理解就是, OC 的代码,通过 JSCore这么个东西,在 OC 和 JS 之间架起一个桥梁.

上图的理解就是,每一个JavaScript上下文(JSContext对象)都归属于一个虚拟机(JSVirtualMachine)。每个虚拟机可以包含多个不同的上下文,并允许在这些不同的上下文之间传值(JSValue对象)。
然而,每个虚拟机都是完整且独立的,有其独立的堆空间和垃圾回收器(garbage collector ),GC无法处理别的虚拟机堆中的对象,因此你不能把一个虚拟机中创建的值传给另一个虚拟机。

本篇笔记的重点是了解下这个调用过程中的并发机制.

JavaScriptCore API都是线程安全的。你可以在任意线程创建JSValue或者执行JS代码.
然而,所有其他想要使用该虚拟机的线程都要等待。

来看下面这段代码来分析

JSContext *context = [[CustomJSContext alloc] init];
JSContext *context1 = [[CustomJSContext alloc] init];
JSContext *context2 = [[CustomJSContext alloc] initWithVirtualMachine:[context virtualMachine]];
NSLog(@"start");
dispatch_async(queue, ^{
    while (true) {
        sleep(1);
        [context evaluateScript:@"log('tick')"];
    }
});
dispatch_async(queue1, ^{
    while (true) {
        sleep(1);
        [context1 evaluateScript:@"log('tick_1')"];
    }
});
dispatch_async(queue2, ^{
    while (true) {
        sleep(1);
        [context2 evaluateScript:@"log('tick_2')"];
    }
});
[context evaluateScript:@"sleep(5)"];
NSLog(@"end");

先通过一个图来了解上面的过程.


iOS JavaScriptCore 笔记一 — 初识_第2张图片
流程示意图

我们要明确的一点是,线程和虚拟机不存在谁包含谁的概念.我们的并发还是根据 GCD 多线程来理解.只是在某个子队列中执行某个JSContext时,也许会发生当前的JSContext所在的虚拟机被占用的情况,导致线程需要等待他执行完以后才能继续.

上面的代码前提为, context 和 context2处于同一个虚拟机, context1是另一个虚拟机.
根据 上面的代码,我们可以理解为(以下按步骤描述)

  • 主队列执行 start 打印
  • 主队列执行 context 的5s 的休眠.
  • 此时并发的子队列 queue 进入了 while 循环,休眠1s 后去执行 context 打印,发现 JS 中的上一步5s 休眠还未执行完毕,因此在此等待.
  • 并发的子队列 queue1也 进入了 while 循环,因为是独立的虚拟机,因此可以产生每隔1s 的打印
  • 并发的子队列 queue2页进入了 while 循环,此时因为 context2 和 context 处于同一个虚拟机,被 context 占用,因此他这里的打印也不会执行.

因此,最后的打印结果应该是

start
tick_1
tick_1
tick_1
tick_1
end
tick
tick_2

你可能感兴趣的:(iOS JavaScriptCore 笔记一 — 初识)