javascriptnode.jsrecursionqdeferred

Node.js recursive calls with q framework for multiple GET requests


After searching stack overflow and the Q documentation I do unfortunately still not understand the q.ninvoke function. I wonder if someone could explain me how it works with my scenario:

I am GET-ing a result of a fetchXml request which returns at most 5000 entries. I wanted to implement a method which calls itself (over a chain) until no pagingcookie is responded by the server anymore.

In the end all results should get concatenated over the recursion to the top of the recursion...

var tryReexecuteForNext5000Entries = function(entitySetName, fetchXml, args){
    var deferred = q.defer();
    var response = args[0];    
    var jsonBody = args[1];
    var fetchXmlPagingCookieResponse = jsonBody["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"];

    if(!fetchXmlPagingCookieResponse){        
        deferred.resolve(args);
        return deferred.promise;
    }

    var pagingArgs = getPagingArgs(fetchXmlPagingCookieResponse);
    var pageNumber = pagingArgs[0];
    var pagingCookie = transformCookieForFetch(pagingArgs[1]);
    fetchXml = injectPagingArgsIntoFetchXml(fetchXml, pageNumber, pagingCookie);

    
    getWithFetchXml(entitySetName, fetchXml)        //recursion!
         .done(function(bodyValue){
             args[1].value = args[1].value.concat(jsonBody.value).concat(bodyValue);
             deferred.resolve(args);
        }
        .fail(function(error){
            deferred.reject(error);
        }));

    return deferred.promise;
}

function getWithFetchXml(entitySetName, fetchXml){
    return AuthProvider.retrieveToken()
        .then(createFetchOptions.bind(this, entitySetName, fetchXml))
        .then(addProxyToOptions)
        .then(executeRequest)
        .then(checkResponse)
        .then(tryReexecuteForNext5000Entries.bind(this, entitySetName, fetchXml))
        .then(onRequestSucceeded.bind(this, "successfully GET fetchXml against CRM"))
        .fail(onFail.bind(this, "webApiRequest.getWithFetchXml: failed to GET with fetchXml: \r\n"+fetchXml));
}

with this setup Q throws me

"TypeError: Cannot read property 'apply' of undefined"

Should work as follows:


Solution

  • it was a stupid syntactical mistake... sorry for that, I have not setup my VisualStuidoCode for good feedback when developing javascript.

    the problem was:

    getWithFetchXml(entitySetName, fetchXml)        //recursion!
            .done(function(bodyValue){
                 args[1].value = jsonBody.value.concat(bodyValue);
                 deferred.resolve(args);
            }
            .fail(function(error){
                deferred.reject(error);
            }));
    

    WRONG BRACKETS! should be:

    getWithFetchXml(entitySetName, fetchXml)        //recursion!
                .then(function(bodyValue){
                     args[1].value = jsonBody.value.concat(bodyValue);
                     deferred.resolve(args);
                })
                .fail(function(error){
                    deferred.reject(error);
                });
    

    Here is my running code for recursive JavaScripts in Node.js:

    function getWithFetchXml(entitySetName, fetchXml){
        return getWithFetchXmlRecursive(entitySetName, fetchXml, null);
    }
    
    var getWithFetchXmlRecursive = function(entitySetName, fetchXml, page){
        return AuthProvider.retrieveToken()
            (...)
            .then(tryReexecuteForNext5000Entries.bind(this, entitySetName, fetchXml, page))
            .then(onRequestSucceeded.bind(this, "successfully GET fetchXml against CRM"))
            .fail(onFail.bind(this, "webApiRequest.getWithFetchXml: failed to GET with fetchXml: \r\n"+fetchXml));
    }
    
    var tryReexecuteForNext5000Entries = function(entitySetName, fetchXml, page, args){
        (...)
        var fetchXmlPagingCookieResponse = jsonBody["@Microsoft.Dynamics.CRM.fetchxmlpagingcookie"];        
        var onRecursionSucceeded = function(bodyValue){
            args[1].value = jsonBody.value.concat(bodyValue);
            deferred.resolve(args);
        }
        var onRecursionFailed = function(error){deferred.reject(error);};
    
        if(!fetchXmlPagingCookieResponse){        
            deferred.resolve(args);
            return deferred.promise;
        }
        (...)
        console.log("webApiRequest.tryReexecuteForNext5000Entries: there is more! starting recursive request with depth: " + (page-1));
        getWithFetchXmlRecursive(entitySetName, fetchXml, ++page)        //recursion!
            .then(onRecursionSucceeded)
            .fail(onRecursionFailed);
    
        return deferred.promise;
    }