skip to Main Content

I’m relatively new to js so please forgive me if my wording isn’t quite right. I’ve also created a jsfiddle to demonstrate the issue.

Overview

In the app I’m working on, I have a function with a jquery ajax call, like this:

function scenario1(ajaxCfg) {
    return $.ajax(ajaxCfg)
}

I want to change this function, but without in any way changing the inputs or outputs (as this function is called hundreds of times in my application).

The change is to make a different ajax call, THEN make the call specified. I currently have it written like this:

function callDependency() { //example dependency
    return $.ajax(depUri)
}

function scenario2(ajaxCfg) {
    return callDependency().then(() => $.ajax(ajaxCfg))
}

Desired Result

I want these two returned objects to be identical:

let result1 = scenario1(exampleCall)
let result2 = scenario2(exampleCall)

More specifically, I want result2 to return the same type of object as result1.

Actual Result

result1 is (obviously) the result of the ajax call, which is a jqXHR object that implements the promise interface and resolves to the same value as result2, which is a standard promise.

Since result2 is not a jqXHR object, result2.error() is undefined, while result1.error() is defined.

I did attempt to mock up these methods (simply adding a .error function to the return result, for example), but unfortunately even when doing this, result1.done().error is defined while result2.done().error is undefined.

Wrapping (or unwrapping) it up

In a nutshell, I want to return the jqXHR result of the .then() lambda function in scenario2 as the result of the scenario2 function. In pseudocode, I want:

function scenario2(ajaxCfg) {
    return callDependency().then(() => $.ajax(ajaxCfg)).unwrapThen()
} //return jqXHR

3

Answers


  1. I feel like your life would be made a lot easier if you used async/await syntax. Just remember though that async functions return a promise. So you could instead write:

    async function scenario2(ajaxCfg) {
        let jqXhrResult;
        try {
            await callDependency();
            jqXhrResult = {
                jqXhr: $.ajax(ajaxCfg)
            };
        } catch() {
            // Error handling goes here
        }
    
        return jqXhrResult;
    }
    
    Login or Signup to reply.
  2. What about something like this? The approach is a little different, but in the end you can chain .done() etc. to the scenario2() function:

    const exampleCall = { url: 'https://code.jquery.com/jquery-1.12.4.min.js'};
    const depUri = { url: 'https://code.jquery.com/jquery-1.12.4.min.js'};
    
    function callDependency() { //example dependency
        return $.ajax(depUri).done(() => console.log('returned callDependancy'))
    }
    
    let obj = { //creating an object with the scenario2 as a method so that I can bind it with defer.promise()
        scenario2: function(ajaxCfg) {
            return $.ajax(ajaxCfg).done(() => console.log('returned senario2')) // Purposely NOT calling the exampleCall() function yet
        }
    }
    
    defer = $.Deferred(); // Using some JQuery magic to be able to return a jqXHR
    defer.promise(obj); // Set the object as a promise
    defer.resolve(callDependency()); // Invoking the callDependency() by default on promise resolve
    
    obj.done(() => {
        obj.scenario2() // Resolving so the callDependency() function can be called
    }).scenario2(exampleCall).done(() => { // Here you can invoke scenario2 and FINALLY chain whatever you want after everything has been called
        console.log('Here I can chain whatever I want with .done() or .fail() etc.')
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    What I think is cool about this way of doing it is that you can just keep adding methods to the object that you created, and then all your secondary functions that are built on top of callDependency() can be in one place. Not only that, but you can reuse those same methods on top of other AJAX calls.

    Read more about this here.

    I hope this helps!

    Login or Signup to reply.
  3. I actually thought of a way easier way to do this.

    You can do it by adding a method to the function constructor’s prototype object. That way any created function can inherit that method and you can still use the .done() syntax. It’s referred to as prototypal inheritance:

    const exampleCall = { url: 'https://code.jquery.com/jquery-1.12.4.min.js'};
    const depUri = { url: 'https://code.jquery.com/jquery-1.12.4.min.js'};
    
    function callDependency() {
        return $.ajax(depUri).done(() => console.log('returned callDependancy'))
    }
    
    Function.prototype.scenario2 = function(ajaxCfg, ...args) {
        return this(...args).then(() => $.ajax(ajaxCfg))
    }
    
    callDependency.scenario2(exampleCall).done(data => {
        console.log(data)
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search