Cocos2dx 3.X jsb加载JavaScript源码文件分析:
1、其实js和lua差不多,lua中通过require函数加载lua文件,js中也是通过一个函数require,加载js源码文件,而且思路差不多,那这个函数是如何执行的呢?
2、require函数
在ScriptingCore.cpp文件中有个registerDefaultClasses函数,这个函数注册了一些C++ 函数供javascript调用,require就是其中之一:
void registerDefaultClasses(JSContext* cx,JS::HandleObject global) {
………不需要的东西,都去掉了。
// register some global functions
//这里就是重点,注册了一个require函数,实际调用的是
/**
* run a script from script :)
*/
static bool executeScript(JSContext *cx,uint32_t argc,jsval *vp);
函数,找到源头,我们可以去看下代码,具体如何实现得了。
JS_DefineFunction(cx,global,"require",ScriptingCore::executeScript,1,JSPROP_READONLY | JSPROP_PERMANENT);
//顺便说下这个,这个log如果是jsb可以直接使用,但不能在h5上面使用,所以最好还是使用cc.log
JS_DefineFunction(cx,"log",ScriptingCore::log,JSPROP_READONLY | JSPROP_PERMANENT);
}
3、
//这个函数是我们的重点
bool ScriptingCore::executeScript(JSContext *cx,jsval *vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc,vp);//获取参数
if (argc >= 1) {
JSString* str = JS::ToString(cx,JS::RootedValue(cx,args.get(0)));
JSStringWrapper path(str);
bool res = false;
if (argc == 2 && args.get(1).isString()) {
JSString* globalName = args.get(1).toString();
JSStringWrapper name(globalName);
JS::RootedObject debugObj(cx,ScriptingCore::getInstance()->getDebugGlobal());
if (debugObj) {
res = ScriptingCore::getInstance()->runScript(path.get(),debugObj);
} else {
JS_ReportError(cx,"Invalid global object: %s",name.get());
return false;
}
} else {
JS::RootedObject glob(cx,JS::CurrentGlobalOrNull(cx));
res = ScriptingCore::getInstance()->runScript(path.get(),glob);
}
return res;
}
args.rval().setUndefined();
return true;
}
------》》其实最终都是执行这个path就是我们传进来,也就是想要加载的js文件
ScriptingCore::getInstance()->runScript(path.get(),glob);
4、这个函数就是真正加载的函数:
bool ScriptingCore::runScript(const char *path,JS::HandleObject global,JSContext* cx)
{
if (cx == NULL) {
cx = _cx;
}
//进行编译
compileScript(path,cx);
JS::RootedScript script(cx,getScript(path));
bool evaluatedOK = false;
if (script) {
//编译完后,就可以调用JS_ExecuteScript函数执行了。
JS::RootedValue rval(cx);
JSAutoCompartment ac(cx,global);
evaluatedOK = JS_ExecuteScript(cx,script,&rval);
if (false == evaluatedOK) {
cocos2d::log("(evaluatedOK == JS_FALSE)");
JS_ReportPendingException(cx);
}
}
return evaluatedOK;
}
5、编译函数
void ScriptingCore::compileScript(const char *path,JSObject* global,JSContext* cx)
{
if (!path) {
return;
}
if (getScript(path)) { //如果已经编译过,则直接返回,这里有一个缓存
// name ~> JSScript map
static std::unordered_map<std::string,JSScript*> filename_script;
return;
}
cocos2d::FileUtils *futil = cocos2d::FileUtils::getInstance();
if (global == NULL) {
global = _global.ref().get();
}
if (cx == NULL) {
cx = _cx;
}
JSAutoCompartment ac(cx,global);
JS::RootedScript script(cx);
JS::RootedObject obj(cx,global);
// a) check jsc file first //先测试字节码,我们一般把js文件弄成字节码,防止被人使用
std::string byteCodePath = RemoveFileExt(std::string(path)) + BYTE_CODE_FILE_EXT;
// Check whether '.jsc' files exist to avoid outputing log which says 'couldn't find .jsc file'.
if (futil->isFileExist(byteCodePath))
{ //如果找到字节码文件,则进行JS_DecodeScript解码
Data data = futil->getDataFromFile(byteCodePath);
if (!data.isNull())
{
script = JS_DecodeScript(cx,data.getBytes(),static_cast<uint32_t>(data.getSize()),nullptr);
}
}
// b) no jsc file,check js file, 如果没有jsc字节码文件,则找js文件
if (!script)
{
/* Clear any pending exception from prevIoUs Failed decoding. */
ReportException(cx);
std::string fullPath = futil->fullPathForFilename(path);
JS::CompileOptions op(cx);
op.setUTF8(true);
op.setFileAndLine(fullPath.c_str(),1);
bool ok = false;
//这里对不同平台有个不同的处理,主要是存放文件的方式不同,然后调用
JS::Compile编译即可。
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
std::string jsFileContent = futil->getStringFromFile(fullPath);
if (!jsFileContent.empty())
{
ok = JS::Compile(cx,obj,op,jsFileContent.c_str(),jsFileContent.size(),&script);
}
#else
ok = JS::Compile(cx,fullPath.c_str(),&script);
#endif
if (ok) {
filename_script[fullPath] = script;
}
}
else {
filename_script[byteCodePath] = script;
}
}
原文链接:https://www.f2er.com/cocos2dx/341392.html