本文研究58fair 动态化界面逻辑js JavascriptCore对象的创建与释放
页面js
一个Fair动态化界面的逻辑js文件实例为:
javascript
GLOBAL['test1#1'] = (function(__initProps__) {
const __global__ = this;
return runCallback(function(__mod__) { //runCallback 在fair_jsbase.js中定义
with(__mod__.imports) {
function _Test5NetPluginState() {
const inner = _Test5NetPluginState.__inner__;
if (this == __global__) {
return new _Test5NetPluginState({
__args__: arguments
});
} else {
const args = arguments.length > 0 ? arguments[0].__args__ || arguments : [];
inner.apply(this, args);
_Test5NetPluginState.prototype.ctor.apply(this, args);
return this;
}
}
_Test5NetPluginState.__inner__ = function inner() {
this._page = 0;
};
_Test5NetPluginState.prototype = {
requestData: function requestData() {
const __thiz__ = this;
with(__thiz__) {
_page++;
FairNet.requestData({
method: 'GET',
url: 'https://wos2.58cdn.com.cn/DeFazYxWvDti/frsupload/3be6c61070d3b48c8165af5d18464c0e_hotel_list_data.json',
data: convertObjectLiteralToSetOrMap({
['page']: _page,
['pageName']: 'test1#1',
}),
success: function dummy(resp) {
if (resp == null) {
return null;
}
let data = resp.__op_idx__('data');
setState('test1#1', function dummy() {});
}
});
}
},
};
_Test5NetPluginState.prototype.ctor = function() {};;
return _Test5NetPluginState();
}
}, []);
})(convertObjectLiteralToSetOrMap(JSON.parse('{}')));
其中runCallback方法在全局js fair_base.js中定义:
ini
function runCallback(func, deps) { //
const imports = {};
const __global__ = this;
deps.map((d) =>
typeof d == "number"
? runModule(d, { exports: imports })
: runModule(d[0], { exports: imports }, d[1])
);
return func.call(__global__, { imports });
}
分析如上jsScript如下:
GLOBAL['test1#1'] = (function(__initProps__) {...})(convertObjectLiteralToSetOrMap(JSON.parse('{}')));
:这行代码定义了一个全局函数test1#1
,该函数的实现是一个自执行的函数。这个自执行的函数接受一个参数__initProps__
,但在这个代码段中,它的值被设置为一个空对象。接下来,这个函数内部使用了一个名为runCallback
的函数,该函数是从fair_jsbase.js
中导入的。runCallback
函数的目的是运行给定的函数func
,并且可以传递一些依赖项。它创建了一个名为imports
的空对象,并且将当前的全局对象__global__
存储在__global__
变量中。然后,它循环处理依赖项(在这里没有提供详细信息),对于每个依赖项,它可能会运行模块并将其输出存储在imports
中。- 在
runCallback
函数的最后,它通过调用func.call(__global__, { imports })
来运行传入的函数func
,并且传递了一个包含imports
对象的参数。 - 在这个特定的代码片段中,传给
runCallback
的函数是一个大函数,它定义了一个名为_Test5NetPluginState
的构造函数和一些方法。这个构造函数似乎用于创建一个对象,该对象可以执行一些网络请求和操作。
总结:这段 JavaScript 代码创建了一个全局函数 test1#1
,这个函数的实现是一个自执行的函数,它使用 runCallback
函数来处理依赖项并运行给定的函数。在这个特定的示例中,给定的函数定义了一个构造函数 _Test5NetPluginState
和一些方法,用于执行网络请求等操作。
全局基础通用js
json
{
"coreJs": {
"fair_core": "packages/fair/assets/fair_core/fair_core.js",
"fair_jsbase": "packages/fair/assets/fair_core/fair_jsbase.js",
"fair_common_plugin": "packages/fair/assets/fair_core/fair_common_plugin.js"
}
}
其他可能添加的通用插件js:
json
{
"plugin": {
}
}
fair_image_picker.js
fair_log_plugin.js
fair_navigator_plugin.js
fair_net_plugin.js
fair_permission.js
fair_toast_plugin.js
fair_url_launcher_plugin.js
全局js文件是在FairApp即FairWidget顶层Widget中,FairApp初始化静态方法runApplication中调用:
scss
Runtime().loadCoreJs(package: package, jsPlugins: jsPlugins, baseJsSources: baseJsSources).then((value) => runApp(app));
- fair_home.json
- fair_basic_config.json
- 以及FairApp 的runApplication方法的jsPlugins参数
- baseJsSources 参数
这4个地方定义JS文件,文件读取为字符串拼装成一个大jsSource内容,所有基础的全局js方法都在这里加载了:
arduino
map[FairMessage.PATH] = baseJsSource + ' ; ' + pluginJsSource;
map[FairMessage.PAGE_NAME] = 'loadCoreJs';
return _channel!.loadJS(jsonEncode(map), null);
调用channel:_methodChannel!.invokeMethod('loadMainJs', args);
对应的native执行为:
ini
// 异步注入到JSContext里
[[FairJSBridge sharedInstance] evaluateScriptWithJSScriptAsync:JSScript callback:callback];
JSValue *jsValue = [self.context evaluateScript:jsScript];
FairWidget展示时候:注入页面js
在FairWidget state的didChangeDependencies 中调用:
_mFairApp.runtime.addScript(state2key, resolveJS, widget.data):
ini
var map = <dynamic, dynamic>{};
map[FairMessage.PATH] = scriptSource;
map[FairMessage.PAGE_NAME] = pageName;
return _channel!.loadJS(jsonEncode(map), null);
对应跳转到Native执行注入JS:
scss
- (JSValue *)evaluateScript:(NSString *)jsScript callback:(FairCallback)callback
{
JSValue *jsValue = [self.context evaluateScript:jsScript]; //GLOBAL['test1#1']=(函数)(json对象)
if (callback) {
callback(jsValue, nil);
}
return jsValue;
}
FairWidget页面关闭时候释放 JS:
在 FairState的dispose方法中释放资源:
runtime.release(key);
ini
@override
void release(String? pageName) {
var map = <dynamic, dynamic>{};
map[FairMessage.FUNC_NAME] = FairMessage.RELEASE_JS;
var msg = FairMessage(pageName, FairMessage.METHOD, map);
_channel?.release(jsonEncode(msg.from()), null);
}
对应native实现为:
objectivec
- (void)disposePage:(NSString *)pageName
{
if (FAIR_IS_NOT_EMPTY_STRING(pageName)) {
self.context[pageName] = nil; //test1#2
}
}
JS注入与释放
self.context[pageName] = nil
// pageName:"test1#1"
[self.context evaluateScript:jsScript]
//jsScript:GLOBAL['test1#1'] = (function(__initProps__) {...})(convertObjectLiteralToSetOrMap(JSON.parse('{}')));
通过这样的成对配置,就完成了Javascript GLOBAL对象的创建与释放,避免了内存的泄漏。