1

I'm having an issue with calling functions within a loop across different modules using requirejs. The function call within the loop resides in module A and executes a function in module B that fires off an Ajax request using jQuery. Each iteration of the loop fires off a different request with different arguments being passed to module B's function that fires off the Ajax request. When the success function of the Ajax request executes, I find that all my argument values are always the values of the last Ajax call made, for all 4 separate Ajax calls.

I've done some googling and it sounds like this is a pretty common problem when executing a function within a loop. The fix tends to be to break out the function call into a different function, creating a different scope. Since my loop and Ajax calls are in 2 different modules I had assumed this would solve that issue, however it still persists.

I've tried some solutions in other stack overflow posts like: JSlint error 'Don't make functions within a loop.' leads to question about Javascript itself and How to pass parameter to an anonymous function defined in the setTimeout call? without success. Anyone have any idea?

Sample code for loop module A:

define(["mpos"],
    function(mpos){

        var monitor = {
            startMonitoring : function(poolObj){    
                // Start Monitoring
                $.each(mpos.msgs, function(action,callback){
                    poolObj.action = action;
                    mpos.sendApiRequest(poolObj,action,callback);

                });
            }
        };

        return monitor;
    }
);

Sample code for Ajax module B - this module is referenced as mpos in module A

define(["mule","constants"],
function(mule,constants){

    var mpos = {
        sendMessage : function(postData,callback,$poolOut){

            return $.ajax({
                'type':'post',
                'url':constants.URLS.proxy,
                'data':{'url':postData},
                success : function(data){
                    // if we have $poolOut we know this is a mpos call
                    if($poolOut != undefined){
                        var keys = Object.keys(data);
                        // add poolOut to data
                        data.poolOut = $poolOut;

                        var poolObj = $poolOut.data('poolObj');
                        if(poolObj){
                            var action = poolObj.action;
                            console.log(poolObj,action);
                            if(action){
                                if(action == "getuserstatus"){
                                    mule.registerPool(poolObj);
                                }
                            } else {
                                log.error("No action on poolObj while attempting to calculate the need for a registerPool call");
                            }
                        }
                    }
                    // parse data
                    callback.apply(this, data);
                },
                error : function(x,h,r){ ... },
                dataType : 'json'
            });
        },
        sendApiRequest : function(poolObj,action,callback){
            var url = poolObj.url + '&page=api&action=' + action;

            var $poolOut = constants.cache.monitorOutput.find('.pool-out.' + poolObj.id);

            var dfd = mpos.sendMessage(url,callback,$poolOut);

            $.when(dfd).always(function(){
                var refreshTimer = setTimeout(function(){
                    if(constants.state.monitorEnabled){
                        mpos.sendApiRequest(poolObj, action, callback);
                    }
                }, poolObj.refreshRate);

            });
        },
        msgs : {
            "getuserstatus" : function(data){ ... },
            "getpoolstatus" : function(data){ ... },
            "getuserworkers" : function(data){ ... },
            "getuserbalance" : function(data){ ... }
        }
    };

    return mpos;
}
);

Thanks!

Community
  • 1
  • 1
ZapRowsdower910
  • 3,024
  • 1
  • 17
  • 14
  • Have you tried to copy your non-working code under the same module? I guess the problem is with your code, not with the requirejs, but maybe I am wrong... – inf3rno Mar 01 '14 at 21:58

1 Answers1

1

NOTE: I am assuming that $poolOut.data('poolObj') is being used to find the poolObj instance passed in the call to startMonitoring, and will return the same instance each time.

You state, "Each iteration of the loop fires off a different request with different arguments being passed to module B's function that fires off the Ajax request."

This statement is not correct. Each iteration fires off a different request with the first argument poolObj being the same in each iteration.

In your .each iteration, you are overwriting the value of poolObj.action before each call to sendApiRequest.

In the AJAX success handler, which is likely invoked after all iterations have completed, the value of poolObj.action will have the value you set it to in the last iteration.

To solve this, I think you need to pass action as a parameter to sendMessage, too, so that a separate value is being stored in the closure for each function call.

var mpos = {
    sendMessage : function(postData,action,callback,$poolOut){

        return $.ajax({
            'type':'post',
            'url':constants.URLS.proxy,
            'data':{'url':postData},
            success : function(data){
                // if we have $poolOut we know this is a mpos call
                if($poolOut != undefined){
                    var keys = Object.keys(data);
                    // add poolOut to data
                    data.poolOut = $poolOut;

                    var poolObj = $poolOut.data('poolObj');
                    if(poolObj){
                        // action is not guaranteed to be the same as poolObj.action here,
                        // since poolObj.action may have changed since this function was first called
                        console.log(poolObj,action);
                        if(action){
                            if(action == "getuserstatus"){
                                mule.registerPool(poolObj);
                            }
                        } else {
                            log.error("No action on poolObj while attempting to calculate the need for a registerPool call");
                        }
                    }
                }
                // parse data
                callback.apply(this, data);
            },
            error : function(x,h,r){ ... },
            dataType : 'json'
        });
    },
    sendApiRequest : function(poolObj,action,callback){
        var url = poolObj.url + '&page=api&action=' + action;

        var $poolOut = constants.cache.monitorOutput.find('.pool-out.' + poolObj.id);

        var dfd = mpos.sendMessage(url,action,callback,$poolOut);

        $.when(dfd).always(function(){
            var refreshTimer = setTimeout(function(){
                if(constants.state.monitorEnabled){
                    mpos.sendApiRequest(poolObj, action, callback);
                }
            }, poolObj.refreshRate);

        });
    },
    msgs : {
        "getuserstatus" : function(data){ ... },
        "getpoolstatus" : function(data){ ... },
        "getuserworkers" : function(data){ ... },
        "getuserbalance" : function(data){ ... }
    }
};
Monroe Thomas
  • 4,962
  • 1
  • 17
  • 21
  • Yep, I had a massive logic issue here. Trying to reuse the same obj for each iteration as if it was a new obj. Not sure how I missed this for hrs and hrs. Thanks for you input, helped a ton! – ZapRowsdower910 Mar 02 '14 at 00:19