How to use promises, or complete an ajax request before the function finishes?

As per the documentation you dont need to wrap the ajax with a promise which already implements promise. Instead chain the response as explained below.

The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the Promise interface, giving them all the properties, methods, and behavior of a Promise (see Deferred object for more information)

You can do something like below by chaining the response:

function isStaff(url, post) {
    return $.ajax({
        url: url,
        dataType:"json"
    }).then(function(resp){
        //resp = $.parseJSON(resp); /*You dont require this if you have respose as JSON object. Just Specify it in 'dataType'*/
        var source = $('#feed-item-template').html();
        var template = Handlebars.compile(source);
        var context = {
            id: post.id,
            content: post.text,
            author: post.author,
            date: $.timeago(post.date),
            staff: resp.is_staff === 1 ? true : false
        };

        return template(context);
    });
}

isStaff(url, post).done(function(template){
    /*Your compiled template code is available here*/
}).fail(function(jqXHR, textStatus, errorThrown){
   console.log("Error:"+textStatus);
});

Note: Be sure to implement error callbacks also. Because you may never know what went wrong :)


Simple explanation about promise with $.defer:

For understanding i have created the Fiddle similar to your requirement.

Explanation:

Basically Promise is been introduced to attain synchronous execution of asynchronous JS code.

What do you mean by Async or Asynchronous code?

The code that is executed may return a value at any given point of time which is not immediate. Famous example to support this statement would be jquery ajax.

Why is it required?

Promise implementations helps a developer to implement a synchronous code block which depends on asynchronous code block for response,. like in ajax call when i make a request to server asking for a data string, i need to wait till the server responds back to me with a response data string which my synchronous code uses it to manipulate it , do some logic and update the UI.

Follow this link where the author has explained with detailed examples.

PS: Jquery $.defer implements or wraps promise in quite a different way. Both are used for the same purpose.


First, let's simplify the compilePost function. This function should know how to compile a post in a synchronous manner. Let's change the isStaff fetching to a simple argument.

function compilePost(post, isStaff) {
    var source = $('#feed-item-template').html();
    var template = Handlebars.compile(source);
    var context = {
        id: post.id,
        content: post.text,
        author: post.author,
        date: $.timeago(post.date),
        staff: isStaff
    }

    var html= template(context);
    return html;
}

Now, let's create a new method, with a single purpose - checking if a user is member of the staff:

function checkForStaffMemebership() {
    return new Promise(function (resolve, reject) {
        $.ajax({
            url: url,
            success: function (data) {
                var session = $.parseJSON(data);
                if (session.is_staff === 1) {
                    resolve(true);
                } else {
                    resolve(false);
                }
            }
        });
    });
}

This function wraps your original ajax call to the server with a promise, whenever the $.ajax call gets a response from the server, the promise will resolve with the answer whether the user is a staff member or not.

Now, we can write another function to orchestrate the process:

function compilePostAsync(post) {
    return checkForStaffMemebership()
        .then(function (isStaff) {
            return compilePost(post, isStaff);
        });
}

compilePostAsync finds out whether the user is a staff member or not. Then, it's compiling the post.

Please notice that compilePostAsync returns a promise, and thus if you used to have something like:

element.innerHTML = compilePost(post);

Now, you should change it to something like:

compilePostAsync(post).then(function (compiledPost) {
    element.innerHTML = compiledPost;
});

Some notes:

  1. This is only an example, it surely misses some things (proper error handling for example)
  2. The isStaff and checkForStaffMemebership (original and new) do not get any argument, I guess you'd figure out how to pass the userId or any other data you might need
  3. Read about promises, it's a useful tool to have, there is a lot of data about it on the web, for example: MDN.