来源:CSDN 发布会员:新书城收集整理 发布时间:2006-7-12 人气:18
|
DWREngine 作为dwr客户端的stub,_execute是其核心方法 正因为是stub,所以你几乎不会直接使用这个方法,通常你会在服务器的dwr.xml定义需要暴露的service及其可调用方法,dwr会根据这个配置文件自动生成一个js文件,对应你暴露的service及其方法,你会在本地调用js文件定义的方法,和调用java的方法一样,除了多了一个回调参数,然后这个方法会委托DWREngine._execute发出请求 /** * @private Send a request. Called by the Javascript interface stub * @param path part of URL after the host and before the exec bit without leading or trailing /s * @param scriptName The class to execute * @param methodName The method on said class to execute * @param func The callback function to which any returned data should be passed * if this is null, any returned data will be ignored * @param vararg_params The parameters to pass to the above class */ //函数定义 DWREngine._execute = function(path, scriptName, methodName, vararg_params) { //定义标记,由此标记才能发请求 var singleShot = false;
//实例化一个_batch封装请求 if (DWREngine._batch == null) { DWREngine.beginBatch(); singleShot = true; } // To make them easy to manipulate we copy the arguments into an args array //定义一个数组存储远程方法请求的参数,通常情况下第一个是回调函数,后面才是与远程方法对应的//形参 var args = [];
//从函数参数的第4个开始算,因为前3个不算,前3个分别是服务器端的请求路径,远程服务脚本名,//远程服务的方法 for (var i = 0; i < arguments.length - 3; i++) { args[i] = arguments[i + 3]; }
//设置请求路径 // All the paths MUST be to the same servlet if (DWREngine._batch.path == null) { DWREngine._batch.path = path; } else { if (DWREngine._batch.path != path) { DWREngine._handleError("Can't batch requests to multiple DWR Servlets."); return; } } // From the other params, work out which is the function (or object with // call meta-data) and which is the call parameters
//定义表量代表纯粹的远程方法的参数 var params; //定义变量代表本地回调函数 var callData; //取出请求参数的第一个,通常是回调函数 var firstArg = args[0]; //取出最后一个,通常是远程方法的参数(一般情况下,除了第一个其他都是) var lastArg = args[args.length - 1];
//1)如果第一个参数函数,那么进入if块 if (typeof firstArg == "function") { //实例化callData,然后将请求参数数组的第一个赋给callData,并将第一个参数踢出数组 //也就说此时的请求参数数组是纯粹的远程方法的参数数组 callData = { callback:args.shift() }; //将剔除了回调函数的请求参数数组赋给params params = args; } //2)也许你会采用这种格式即最后一个是回调函数,其他是远程方法参数,那么下个面的if块适合你 else if (typeof lastArg == "function") { callData = { callback:args.pop() }; params = args; } //3)如果你将最后一个请求参数定义为对象且为其设置了callback方法,那么那么下面的if块适合你 else if (typeof lastArg == "object" && lastArg.callback != null && typeof lastArg.callback == "function") { callData = args.pop(); params = args; } //4)如果第一个参数为空,那么进入下面的块 else if (firstArg == null) { // This could be a null callback function, but if the last arg is also // null then we can't tell which is the function unless there are only // 2 args, in which case we don't care!
//如果最后一个参数也为空,但参数大于2,那么就会报错,因为系统不知道到底那一个才是//空的回调函数 if (lastArg == null && args.length > 2) { if (DWREngine._warningHandler) { DWREngine._warningHandler("Ambiguous nulls at start and end of parameter list. Which is the callback function?"); } } callData = { callback:args.shift() }; params = args; } //5)第一参数不为空,最后一个为空,那么将最后一个参数之外的所有参数视为远程方法参数 else if (lastArg == null) { callData = { callback:args.pop() }; params = args; } //6)以上情况都不成立,抛错 else { if (DWREngine._warningHandler) { DWREngine._warningHandler("Missing callback function or metadata object."); } return; }
//通常还是将第一作为回调函数,后面全部是远程方法参数,如果无需回调,第一个为null //好不容易分开了回调函数很远程请求参数,继续前进
// Get a unique ID for this call //产生随机数作为请求ID var random = Math.floor(Math.random() * 10001); var id = (random + "_" + new Date().getTime()).toString(); //定义一个前缀变量 var prefix = "c" + DWREngine._batch.map.callCount + "-"; //将请求ID存入请求对象的ID数组 DWREngine._batch.ids.push(id);
//如果你是将一个对象而非函数作为回调函数,见上面的第3种情况,那么一下一段代码适合你,否则//跳过 // batchMetaData stuff the we allow in callMetaData for convenience
//设置_batch的method属性 if (callData.method != null) { DWREngine._batch.method = callData.method; delete callData.method; }
//设置_batch的verb 属性 if (callData.verb != null) { DWREngine._batch.verb = callData.verb; delete callData.verb; } //设置_batch的async 属性 if (callData.async != null) { DWREngine._batch.async = callData.async; delete callData.async; } 设置_batch的timeout 属性 if (callData.timeout != null) { DWREngine._batch.timeout = callData.timeout; delete callData.timeout; } //如果callData存在preHook ,那么将此preHook 加入_batch的preHook数组的第一个 // callMetaData stuff that we handle with the rest of the batchMetaData if (callData.preHook != null) { DWREngine._batch.preHooks.unshift(callData.preHook); delete callData.preHook; } //如果callData存在postHook ,那么将此preHook 加入_batch的postHooks数组的最后一个 if (callData.postHook != null) { DWREngine._batch.postHooks.push(callData.postHook); delete callData.postHook; }
// Default the error and warning handlers //设置错误处理器和警告处理器 if (callData.errorHandler == null) callData.errorHandler = DWREngine._errorHandler; if (callData.warningHandler == null) callData.warningHandler = DWREngine._warningHandler;
// Save the callMetaData //将回调函数放入_handlersMap对象中,以id作为key或属性 DWREngine._handlersMap[id] = callData;
//设置_batch的map对象 //设置脚本属性 DWREngine._batch.map[prefix + "scriptName"] = scriptName; //设置方法属性 DWREngine._batch.map[prefix + "methodName"] = methodName; //设置id属性 DWREngine._batch.map[prefix + "id"] = id;
// Serialize the parameters into batch.map //为DWREngine添加编码函数 DWREngine._addSerializeFunctions();
//将远程方法参数编码为某种格式 //以下是几种格式的例子 //比如一个一个js字符串的值为323YN2O2,那么编码后成为 "string:323YN2O2" //比如一个对象编码为"Object:{tvUserId:reference:c0-e6, userNo:reference:c0-e7, loginName:reference:c0-e8}" //编码全部存入_batch的map对象 for (i = 0; i < params.length; i++) { DWREngine._serializeAll(DWREngine._batch, [], params[i], prefix + "param" + i); }
//删除DWREngine刚刚添加的编码函数 DWREngine._removeSerializeFunctions();
// Now we have finished remembering the call, we incr the call count //调用此数加1 DWREngine._batch.map.callCount++; //标记为true,发送请求 if (singleShot) { DWREngine.endBatch(); } };
总结:_execute其实只干了两件事情 1)分离回调函数和远程方法参数 2)编码远程方法参数
最后再调用另一个很重要的函数endBatch(其实是_sendData)来完成请求
从_execute方法可以看出DWREngine有个很重要的数据结构就是_batch _batch可以视为请求参数的封装器,其实比这更多 它包含以下几个属性 ids (字符数组),map(对象)(主要包含c0-id.c0-methodName,c0-scriptName,callCount,c0-paramx(x为0或1或2,有几个参数就有几个paramx ),还包含很多细小的参数对象的属性编码,每个编码都为一个属性),paramCount(数值),path(字符串),preHooks(函数数组),postHooks(函数数组) |
源码分析DWR的Engine._execute方法
最新推荐文章于 2020-12-11 04:12:07 发布