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; } }