如果您使用JSContext 的evaluateJavaScript 方法。由于上下文上没有取消方法,因此您无法停止它。而且iOS不喜欢macOS可以使用XPC所以没办法停止外部运行环境。
但是,有一个解决方法。想想JSContext 喜欢浏览器。剧本在路上飞。如何通过外部事件阻止它。最方便的方法是自己构建runloop。将任务变小并放入队列中。
自定义运行循环
我每隔几秒导出一个本机 Timer 以在 downloadWithHandler 方法上调用 javascript 处理程序,并在某个时候将 isCancelled 设置为 true。 runloop 将停止,JSContext eval 到达整个脚本的末尾并返回。
本机:
let script = viewModel.string
let context = EAJSContext()!
// context will be dealloc after finish if not retain here.
// not retain it to debugging
// viewModel.context = context
DispatchQueue.global(qos: .background).async {
// inject helper metholds
JavaScriptCoreHelper().config(context: context)
// export download(handler:) method
Emulator.configure(context: context)
let result = context.evaluateScript(script)
print("context return result: \(result)")
}
脚本:
var emulator = Emulator.create();
var taskIsFinish = false;
const promiseA = new Promise( (resolve, reject) => {
emulator.downloadWithHandler( (response) => {
// native pass dictionary
var isFinish = response["isFinish"];
var isCancelled = response["isCancelled"];
var date = response["date"];
console.log("isFinish: " + isFinish);
console.log("isCancelled: " + isCancelled);
console.log("date: " + date);
if (isFinish || isCancelled) {
resolve(date);
}
});
});
promiseA
.then( (val) => {
console.log("asynchronous logging has val: " + val)
taskIsFinish = true
})
while(!taskIsFinish) {
// long task in queue
sleep(1);
console.log('long task');
}
输出:
2020-05-10 04:07:06.766592+0800 …[34354:2831281] [interaction] … runToolbarItemPressed(_:): run triggerd
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:06 GMT+0800 (CST)
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:06 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:07 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:08 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:10 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: false
console.log: date: Sun May 10 2020 04:07:11 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: true
console.log: date: Sun May 10 2020 04:07:12 GMT+0800 (CST)
console.log: asynchronous logging has val: Sun May 10 2020 04:07:12 GMT+0800 (CST)
console.log: long task
console.log: isFinish: false
console.log: isCancelled: true
console.log: date: Sun May 10 2020 04:07:13 GMT+0800 (CST)
context return result: Optional(undefined)
console.log: isFinish: false
console.log: isCancelled: true
console.log: date: Sun May 10 2020 04:07:13 GMT+0800 (CST)
console.log: isFinish: false
console.log: isCancelled: true
console.log: date: Sun May 10 2020 04:07:13 GMT+0800 (CST)
2020-05-10 04:07:13.391950+0800 …[34354:2831310] [debug] EAJSContext.swift[16], deinit
(如果在 eval 完成后上下文没有 deinit,内存可能会泄漏。)
其他想法
将上下文包装在本地 Worker 类中。并设置标志以使该工作人员在任务取消时以空结果快速返回回调。请勿保留和丢弃。