Эта пара AJAX запрашивает состояние гонки? - PullRequest
2 голосов
/ 07 декабря 2011

Я создаю сайт, который будет содержать новостные статьи. Эти статьи появятся в двух столбцах внизу страницы. Внизу будет кнопка для загрузки дополнительных новостей. Это означает, что мне нужно указать, какую новость загружать. На стороне сервера я просто реализую это с помощью предложения LIMIT в своем выражении SQL, предоставляя параметр: first так:

SELECT * 
FROM news 
ORDER BY `date` DESC 
LIMIT :first, 1

Это означает, что на стороне клиента мне нужно отслеживать, сколько новостей я загрузил. Я реализовал это, сохранив функцию загрузки новой информации в объекте со свойством, содержащим количество загруженных элементов. Я боюсь, что это как-то условие гонки, которого я не вижу, хотя мой loadNewInformation() будет вызван дважды, прежде чем число будет увеличено. Мой код выглядит следующим образом:

var News = {

    newInfoItems: 0,

    loadNewInformation: function(side) {
        this.newInfoItems += 1;
        jQuery.get(
            '/api/news/'+ (this.newInfoItems - 1),
            function(html) {
                jQuery('div.col'+side).append(html);
            }
        );
    }
}

При загрузке страницы это вызывается следующим образом:

News.loadNewInformation('left');
News.loadNewInformation('right');

Я мог бы реализовать это таким образом, чтобы обработчик успеха первого вызова сделал еще один AJAX-запрос для второго, что явно не было бы условием гонки ... но это похоже на небрежный код. Мысли?

Ответы [ 5 ]

1 голос
/ 07 декабря 2011

(Да, есть условие гонки.)

Адресация Только JavaScript

Весь код JavaScript на странице (кроме веб-работников), который включает в себя обратные вызовы, выполняется "взаимно"exclusive ".

В этом случае, поскольку newInfoItems оценивается с нетерпением , он даже не настолько сложен: и" / api / news / 0 ", и" / api / news / 1 "гарантированно будут выбраны (или потерпят неудачу при попытке).Сравните это с:

// eager evaluation: value of url computed BEFORE request
// this is same as in example (with "fixed" increment order ;-)
// and is just to show point
var url = "/api/news/" + this.newInfoItems
this.newInfoItems += 1;
jQuery.get(url, 
    function(html) {
        // only evaluated on AJAX callback - order of callbacks
        // not defined, but will still be mutually exclusive.
        jQuery('div.col'+side).append(html);
    }
);

Однако порядок , в котором завершаются запросы AJAX, не определен и зависит от сервера и браузера.Кроме того, как обсуждается ниже, не существует атомарного контекста, установленного между сервером и отдельными AJAX-запросами .

Обращение к JavaScript в контексте

Теперь, даже если установлено, что"/ api / news / 0" и"/ api / news / 1" будут вызваны, представьте себе, что маловероятно, но теоретически возможно ситуация:

  • статьи B,A существуют в базе данных
  • браузер отправляет оба AJAX-запроса - асинхронно или синхронно, это не имеет значения!
  • статья добавлена ​​в базу данныхиногда между , когда
    • сервер обрабатывает запрос news/0, а
    • сервер обрабатывает news/1запрос

Затем это происходит:

  • news/0 возвращает статью B (статьи B,A в базе данных)
  • статья C добавлено
  • news/1 возвращает статью B (статьи C,B,A в базе данных)

Обратите внимание, что статья B была возвращена дважды !Упс:)

Итак, хотя состояние гонки "кажется маловероятным" , оно существует.Подобное состояние гонки (с другими результатами) может возникнуть, если news/1 обработано до news/0 и (еще раз) добавлена ​​статья между запросами: нет атомарной гарантии в любом случае!

(Приведенное выше условие гонки будет более вероятным , если выполнение запросов AJAX последовательно, поскольку время для добавления новой статьи увеличивается.)

Возможное решение

Подумайте, скажем, о n (2 все в порядке!) Статей в одном запросе (например, "/ api / latest / n"), а затем выложитесоответствующие статьи в обратном вызове .Например, первая половина статей слева и вторая половина справа, или что-то подходящее.

А также устранение вышеупомянутого конкретного состояния расы, делая единственный запрос атомарным действием -Что касается добавления статей - это также приведет к уменьшению сетевого трафика и уменьшению работы сервера.

Выборка для API может выглядеть следующим образом:

SELECT * 
FROM news 
ORDER BY `date` DESC 
LIMIT :n

Счастливое кодирование.

1 голос
/ 07 декабря 2011

Да, технически это может создать условия гонки.Вызовы асинхронные, и если первый по какой-то причине задерживается, второй может вернуться первым.

Однако, поскольку у вас мало что происходит с функциями обратного вызова, которые зависят отприсутствие другой «стороны», населяющей меня, я не понимаю, где это должно причинить вам слишком много горя.

0 голосов
/ 07 декабря 2011

Попробуйте это:

loadNewInformation: function(side) {
    jQuery.get(
        '/api/news/'+ (this.newInfoItems++),
        function(html) {
            jQuery('div.col'+side).append(html);
        }
    );
}
0 голосов
/ 07 декабря 2011

Я полагаю, вы намекаете на счетчик newItemInfo?

Наблюдения:

  1. Вы дважды вызываете News.loadNewInformation с функцией обратного вызова, которая будет выполненапри завершении AJAX.
  2. Предоставленный вами метод обратного вызова не изменяет объект News.

В этом случае вам не о чем беспокоиться.Второй вызов News.loadNewInformation будет выполнен только после завершения первого вызова, то есть за исключением выполнения метода обратного вызова.Следовательно, ваш newItemInfo счетчик будет содержать правильное значение.

0 голосов
/ 07 декабря 2011

Не должно быть никаких условий гонки, должно быть что-то еще не так в вашем коде.Счетчик увеличивается до вашего .get() вызова, поэтому перед каждым получением счетчик должен быть правильно увеличен.Короткий пример, чтобы продемонстрировать, что он работает при последовательном вызове: http://jsfiddle.net/KkpwF/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...