简体   繁体   中英

Ajax Request waiting another ajax request to be executed

I'm developing a chat in PhP and I'm doing long polling for check new messages on server. In Ajax request to do long polling the server checks for up 25 seconds if it has new registered messages. In that time when the server is arriving it does not return anything to the javascript and if I send a new request the browser waits for the checking to finish sending a new message

chat.js

function sndmessage(message, idchat) {

    if (message != "") {

        var $this = $('.chat .msgs');
        var indice = 0;
        var msg = message;

        $('#sendmsg').val("");

        $.ajax({
            url: "../ajax/sendmessage.ajax.php",
            type: "POST",
            data: {
                "message": msg,
                "id": id
            },
            success: function(response) {
                return;
            }
        });
    }

    return true;
}


function polling(idm, idu) {
    var interval;

    $.ajax({
        async: true,
        url: "../ajax/polling.ajax.php",
        data: {
            "idm": idm,
            "idu": idu
        },
        type: "POST",
        dataType: "JSON",
        success: function(response) {
            clearInterval(interval);

            if (response.response == false) {
                interval = setTimeout(function() {
                    polling(idm, idu);
                }, 500);
            } else {
                if ('id' in response[0][0]) {

                    for (var i = 0; i < response[0].length; i++) {

                        if (mensagensIDs.indexOf(response[0][i]['id']) < 0) {
                            mensagensIDs.push(response[0][i]['id']);

                            let data = response[0][i]['data'].split(" "),
                            dia = data[0].split("-").reverse().join().replaceAll(",", "/"),
                            hora = data[1].split(":").slice(0, 2).join(":"),
                            mensagem = response[0][i]['mensagem'],
                            remetente = (response[0][i]['remetente'].indexOf(" - ") > 0) ? "admin" : "usuario",
                            destinatario = (response[0][i]['destinatario'].indexOf(" - ") > 0) ? "admin" : "usuario",
                            id = response[0][i]['id'];

                            let d = new Date();

                            let html = (d.getDate() == dia.split("/")[0]) ? hora : dia + " - " + hora;

                            chats.push({
                                "idu": idu,
                                "chat": {
                                    "id": id,
                                    "class": (remetente == "admin") ? "msg-adm teal lighten-1" : "msg-eu",
                                    "class2": (remetente == "admin") ? "white-text" : "blue-text text-darken-2",
                                    "msg": mensagem,
                                    "tooltip": html,
                                    "tooltippos": (remetente == "admin") ? "right" : "left"
                                }
                            });

                            if (idu == chatatual) {

                                $('.chat .msgs').append('<div id="' + idu + '" class="col s12">\
                                <div class="' + ((remetente == "admin") ? "msg-adm teal lighten-1" : "msg-eu") + ' z-depth-1">\
                                <span class="tooltipped pointer ' + ((remetente == "admin") ? "white-text" : "blue-text text-darken-2") + '" data-position="' + ((remetente == "admin") ? "right" : "left") + '" data-delay="50" data-tooltip="' + html + '">' + mensagem + '</span>\
                                </div>\
                                </div>').animate({
                                    scrollTop: $('.msgs').prop("scrollHeight")
                                }, 500);

                            } else {
                                $('li.collection-item.avatar#' + idu).find('.badge').text("New message");

                            }
                        }

                    }

                    interval = setTimeout(function() {
                        polling(mensagensIDs[mensagensIDs.length - 1], idu);
                    }, 500);

                } else {
                    interval = setTimeout(function() {
                        polling(idm, idu);
                    }, 5000);
                }
            }
        }
    });

}

I want know how to send a request without waiting for the other request

It's actually quite simple. What you're doing is sending the request and calling for the next loop when you get the response and that is not what you want. What you should do is something like:

function polling(idm,idu){
    var interval;
    $.ajax({/*do your stuff here*/});
    setTimeout(function(){pooling(/*whatever*/)}, 500); // See that this is outside the ajax call, so it doesn't wait for the response
}

Why not set the both 'async' in ajax to true? You can send the second ajax without waiting for the first one.

$.ajax({
         'async': true,
         //your code
      })

This kind of thing can be a total nightmare until you know how to work with promises .

The key here is to understand that :

  • jQuery.ajax() returns a promise.
  • the timeout you seek is implemented by racing the promise returned by jQuery.ajax() against a promise that is guaranteed to reject after 25000 ms.

Now, there are two ways to write the code (see footnote 2 for explanation)

using jQuery promises throughout

First two utility functions :

// a promise-returning `delay()` utility, which is the only place that `setTimeout()` is used.
function delay(t) {
    return new jQuery.Deferred(function(dfrd) {
        setTimeout(dfrd.resolve, t);
    }).promise();
}

// a promise-returning `race()` utility which ensures that the first promise in `promises` to resolve/reject will resolve/reject the returned promise.
function race(promises) {
    return new jQuery.Deferred(function(dfrd) {
        promises.forEach(function(p) {
            p.then(function(result) {
                dfrd.resolve(result);
            }, function(reason) {
                dfrd.reject(reason);
            });
        });
    }).promise();
}

Now, polling()

function polling(idm, idu) {
    // first promise
    var ajaxPromise = $.ajax({
        'async': true,
        'url': '../ajax/polling.ajax.php',
        'data': { 'idm': idm, 'idu': idu },
        'type': 'POST',
        'dataType': 'JSON',
    }).then(function(response) {
        if (response.response && ('id' in response[0][0])) {
            // ... lots of synchronous processing ...
            return [mensagensIDs[mensagensIDs.length - 1], idu]; // or maybe `return [mensagensIDs.pop(), idu]`?
        } else {
            return [idm, idu];
        }
    });

    // second promise
    var timeoutPromise = delay(25000).then(function() {
        return new jQuery.Deferred().reject(new Error('long-poll-timeout')).promise();
    });

    // Now the clever bit ...
    // At this point you have two promises, which can be raced against each other.
    // Exactly what happens next, depends on who wins the race.
    // * if `timeoutPromise` wins the race, it will be caught below, the ajax will be aborted, then execution will progress to the second chained `.then()`.
    // * if `ajaxPromise` wins the race, then the `.catch()` clause will be bypassed, and execution will progress directly to the second chained `.then()`.
    return race([ajaxPromise, timeoutPromise])
    .then(null, function(error) { // this is effectively a `.catch()` block.
        console.log(error.message); // you will see 'long-poll-timeout' (or possibly some ajax/http error message).
        ajaxPromise.abort(); // ensure that `ajaxPromise` **doesn't** follow its success path.
        return [idm, idu]; // deliver `[idm, idu]` to the chained .then().
    })
    .then(function(args) { // via one route or other, `[idm, idu]` or `[mensagensIDs[mensagensIDs.length - 1], idu]` is delivered here as `args`.
        return delay(500).then(function() {
            return polling.apply(null, args);
        });
    });
}

using jQuery.ajax() and javascript native Promises

First, one utility function :

// a promise-returning `delay()` utility, which is the only place that `setTimeout()` is used.
function delay(t) {
    return new Promise(function(resolve, reject) {
        setTimeout(resolve, t);
    });
}

Now, polling()

function polling(idm, idu) {
    // first promise
    var ajaxPromise = $.ajax({
        'async': true,
        'url': '../ajax/polling.ajax.php',
        'data': { 'idm': idm, 'idu': idu },
        'type': 'POST',
        'dataType': 'JSON',
    }).then(function(response) {
        if (response.response && ('id' in response[0][0])) {
            // ... lots of synchronous processing ...
            return [mensagensIDs[mensagensIDs.length - 1], idu]; // or maybe `return [mensagensIDs.pop(), idu]`?
        } else {
            return [idm, idu];
        }
    });

    // second promise
    var timeoutPromise = delay(25000).then(function() {
        return Promise.reject(new Error('long-poll-timeout'));
    });

    // Now the clever bit ...
    // At this point you have two promises, which can be raced against each other.
    // Exactly what happens next, depends on who wins the race.
    // * if `timeoutPromise` wins the race, it will be caught below, the ajax will be aborted, then execution will progress to the chained `.then()`.
    // * if `ajaxPromise` wins the race, then the `.catch()` clause will be bypassed, and execution will progress directly to the chained `.then()`.
    return Promise.race([ajaxPromise, timeoutPromise])
    .catch(function(error) {
        console.log(error.message); // you will see 'long-poll-timeout' (or possibly some ajax/http error message).
        ajaxPromise.abort(); // ensure that `ajaxPromise` **doesn't** follow its success path.
        return [idm, idu]; // deliver `[idm, idu]` to the chained .then().
    })
    .then(function(args) { // via one route or other, `[idm, idu]` or `[mensagensIDs[mensagensIDs.length - 1], idu]` is delivered here as `args`.
        return delay(500).then(function() {
            return polling.apply(null, args);
        });
    });
}

Notes:

  1. for detailed explanation see comments in code
  2. it's even simpler with jQuery.ajax's timeout: option but constraints in Firefox 3.0+ make that approach non-universal.
  3. no version of IE (reportedly) includes native Promises.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM