JavaScript sniffing actor – Sniffer.js

First, warm up – first look at the actual code

A.js file

 / / Define Wall and internal methods; (Function (Window, Func, undefined) {var name = 'Wall'; Wall.SAY = Function (Name) {Console.log ('i \' M '+ Name +'! ') }; Wall.Message = {Return Name;}, setname: function (firstname, secondname) {name = firstname + '-' + secondname;}};} (window, window.wall || (window.wall = {});   Index.jsp file 

// Lab.js is a file loading tool // depends on A.JS load, the cached JS method $ LAB.Script (“a.js”). Wait (Function). ) {// Trigger Subscribed method Sniffer.Trigger ({‘base’: window, ‘name’: ‘Wall.SAY’});});
    This, regardless of how much A.js files, Wall.SAY ('Wall') can wait until the file is really loaded, then execute.   Second, Tool Introduction 

// Execute Wall.Message.setname (‘wang’, ‘Wall’); Sniffer.Run ({‘Base’: Wall, ‘Name’: ‘Message.setname’, ‘Subscribe’: true}, ‘Wang’, ‘Wall’);

Look at this execution code, you may feel confused – What ghosts! & # 128518;
 Sniffer.js action is to test the execution method, if it is not executable, it will not be thrown.  , such as Wall.Message.setName ('wang', 'Wall'); 
If the file in this method is not loaded, it will not be reported.
The logic of processing is first cached, and after the method is added, it is called again.

The method called again is as follows:

// Trigger the subscribed method Sniffer.Trigger ({‘base’: Wall, ‘Name’: ‘ Message.setname ‘};

Online Demo: https: // (need In the console, it is recommended to use PC)

to say the birth of this tool, because the company’s business needs, written by itself.

Because the company’s background language is Java, I like to use JSP’s out.print () method to directly output some JS methods to the client.
This has a contradictory point, sometimes the JS file has not been downloaded, the statement output from the background has begun to call the method, which is very embarrassing.
 So,  This tool has two points:  
1. Detecting whether the executionful JS method exists, existence is executed immediately.

2. The cache is a JS method that is not existed. When it is actually executable, then take it from the cache queue, trigger execution.

Third, Sniffing Core Basics – Operators In

By using the operator IN to traverse the method in the namespace, if you get it Value, the representative can be executed. Conversely, the representative is not executable.

Operators in

In this case, you can know the sense of sniffing of this sniffer.js.

/ *** @Function {private} Detection method is available * @Param {string} funcname – method name ***. ***. **** @Param {Object} Base – Method The object ** / function checkmethod (FuncName, Base) {var methodlist = funcname.split (‘.’), // method name list readyfunc = base, // Detects the qualified function section Result = {‘success’: true, ‘func’: Function () {}}}}}}, // Returns the test results MethodName, // Single method name I; for (i = 0; i

like Wall.Message.SetName (‘wang’, ‘Wall’); this Method, to determine if it is executable, you need to perform the following steps:

1. Judging whether the Wall exists in Window. javaScript嗅探执行神器-sniffer.js

2. Wall exists, continue to determine if the Message is in Wall.

3. Message exists, continue to determine if the setName is in Message

4. Finally, it is determined that the representative is executed. . If any of the intermediate detection is not passed, the method is not executable.

V. Implementation Cache
  Cache is implemented using closed bags. With the nature of the queue, stored in List < methodList.length; i++){
 methodName = methodList[i];
 if(methodName in readyFunc){
 readyFunc = readyFunc[methodName];
 result.success = false;
 return result;
 result.func = readyFunc;
 return result; 

; (Fun, undefined) {‘use strict’ var list = []; // Store the required call Method // Perform method = function () {// Many code … // Cake Subscribe Function List.push (…);};}) (window.sniffer || (Window.Sniffer || . Sniffer = {});

1. Designated in the queue Based on the base point

Due to the operation of the operator IN, several base points are required to detect it. So the first thing to have is Base

2. The method name of the detected character type Name

like Wall.Message.setname (‘wang’, ‘ Wall ‘); if the base point {‘ base ‘: Wall} has been specified, Message.setName is also required. So to store Message.setName, that is, {‘base’: Wall,’name’: ‘message.setname’}

3. Parameters of caching methods Args

like Wall.Message.setName (‘wang’, ‘Wall’) , There are two parameters (‘wang’, ‘Wall’), so it needs to be stored. That is, {‘Base’: Wall, ‘Name’: ‘Message.setname’, ‘Args’: [‘WANG’, ‘Wall’]}.

Why is the parameter use an array to cocabulate, because the parameters of the method are changed, so subsequent code requires Apply to do trigger. Similarly, the parameters here needs to be cached with arrays
, so the single item of the cache queue is as follows:
{‘Base’: Wall, ‘Name’: ‘Message.setname’, ‘Args’: [‘WANG’, ‘Wall’]}

Seven, implementing RUN method

; (Fun, undefined) {‘use strict’ var list = []; // Store method to be called to be called / ** * @function function Conversion interface, used to determine if there is a namespace, there is a call, not worthless * @version {create} 2015-11-30 * @Description * Used: Designed for delay loading * Example: Wall.Mytext .init (45, false); * Call: ({‘base’: window, ‘name’: ‘Wall.Mytext.init’}, 45, false; or ({‘base’: Wall, ‘Name’: ‘mytext.init’}, 45, false; * If you don’t know the number of parameters, you cannot write directly, you can call the current method in the way * Example: Apply (Window, [{‘Name’: ‘Wall.Mytext.init’}, 45, false]); ** / = function () {if (arguments.length

The role of the RUN method is whether the detection method is executable, executable, execute. Not executable, according to the incoming parameters, decide whether to cache.

This run The focus of the method is to use Arguments to achieve 0-n parameters free incoming.

The first meticulum Arguments [0], fixed is used to pass the configuration item. Store the base base base, method string argument [0] .name, and cache flag arguments [0] .subscribe.

The second shape is parametric, The method called the parameters required to be used by the method caller.

Use a generic method to convert Arguments to a true array. (Args = (arguments)

Then, cutting the method to call the parameters required. (Funcargs = args.slice (1))
 The arguments process of the RUN method is completed After that, the CheckMethod method can be called to sniff.  According to the result of the sniffing, two cases:  
The sniffing results are executable, Call the APPLY execution

Return Result.func.Apply (Result.Func, Funcargs);

Here the focus is that the role domain is Result.Func, That is, the Wall.Message.setName of an example. In this way, this is not changed if it is used in the method.
 Use return because some method is executed, there is a return value, so it is necessary to add Return to transfer the return value.  < 1 || typeof arguments[0] != 'object'){
 throw new Error(' 参数错误');
 var name = arguments[0].name, // 函数名 0位为Object类型,方便做扩展
 subscribe = arguments[0].subscribe || false, // 订阅当函数可执行时,调用该函数, true:订阅; false:不订阅
 prompt = arguments[0].prompt || false, // 是否显示提示语(当函数未能执行的时候)
 promptMsg = arguments[0].promptMsg || '功能还在加载中,请稍候', // 函数未能执行提示语
 base = arguments[0].base || window, // 基准对象,函数查找的起点
 args =, // 参数列表
 funcArgs = args.slice(1), // 函数的参数列表
 callbackFunc = {}, // 临时存放需要回调的函数
 result; // 检测结果
 result = checkMethod(name, base);
 subscribe = false;
 return result.func.apply(result.func, funcArgs); // apply调整函数的指针指向
 (typeof console != 'undefined') && console.log && console.log('错误:name='+ +'; message='+ e.message);
 // 输出提示语到页面,代码略
 if(subscribe){ = name;
 callbackFunc.base = base;
 callbackFunc.args = funcArgs;
 // 嗅探方法
 function checkMethod(funcName, base){
 // 代码...
})(window.Sniffer || (window.Sniffer = {}));
The sniffing results are unauthorized, depending on the incoming configuration value SUBSCRIBE, decide whether to cache into the queue LIST.

Need a cache, stitching the queue single item, push into the list.

8. To achieve Trigger method

; (Fun, undefined) {‘use strict’ var list = []; // Store the method // execution method of the required call to the subscription, = function () {// code …}; / ** * @function triggers function interface, call the function that has been subscribed in advance * @Param {Object} Option – Related parameters required * @Description * Up: Design is designed to delay loading * In addition, the premise of calling the TRIGGER method is that the JS where the subscription method has been loaded and parsed. * No matter whether the trigger is successful , Will clear the corresponding items in the list ** / fun.trigger = function (option) {if (TypeOf option! == ‘Object’) {throw new error(‘Sniff.trigger parameter error’); return;} var funcname = || ”, // function name base = option.base || window, // benchmark object, function lookup start point newlist = [] , // is used to update list result, // detection results of Pointer I, // Traverse List param; // Temporary Storage List [IF (Funcname); if (FuncName); if (Funcname); if (FuncName In Base);

If the front RUN method is understood, the Trigger method is not difficult to understand.

1. First, to tell Trigger Method, it is necessary to perform which method is executed from the queue List.

2. Before performing the method, you need to sniff if this method has existed. Existence, can be executed. Otherwise However, it can be considered that the method does not exist, can be removed from the cache. Nine, practical and reliability

Practicality This is no Route suspicion, no matter what the code stack, Sniffer.js is worth having!

Reliability, Sniffer.js uses no feedback on any compatible, or performance problem In this regard!

Finally, attach the source code address:

The above is all the contents of this article, I hope this paper will bring some help to everyone’s learning or work, and I hope to support Tumi Cloud!

© Copyright Notice
Just support it if you like
comment Grab the couch

Please log in to comment