Есть ли причина, чтобы использовать синхронные запросы XMLHttpRequest?


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

18 82

18 ответов:

Я думаю, что они могут стать более популярными по мере продвижения стандартов HTML 5. Если веб-приложению предоставляется доступ к веб-работникам, я мог бы предвидеть, что разработчики используют выделенного веб-работника для синхронных запросов, как сказал Джонатан, чтобы гарантировать, что один запрос произойдет раньше другого. В текущей ситуации одного потока это менее чем идеальный дизайн, поскольку он блокируется до завершения запроса.

синхронные XHRs полезны для сохранения пользовательских данных. Если вы справитесь с beforeunload событие вы можете загружать данные на сервер, когда пользователь закрывает страницу.

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

обновление:

ниже намекнул - но не удалось доставить-что с появлением лучшей асинхронной обработки запросов действительно нет причин использовать синхронные запросы, если только намеренно не блокировать пользователей от чего - либо, пока запрос не будет завершен-звучит вредоносно :)

хотя это может звучать плохо, могут быть моменты, когда важно, чтобы запрос (или серия запросов) происходил до того, как пользователь покинет страницу, или перед выполнением действия-блокировка другого выполнения кода (например, предотвращение кнопки "Назад") может уменьшить количество ошибок/обслуживания для A плохо разработанная система; тем не менее, я никогда не видел ее в дикий и подчеркните, что этого следует избегать.

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

как указано в документах Mozilla есть случаи, когда вы должны использовать синхронные запросы; однако, также указан обходной путь, который использует Маяк (недоступно в IE/Safari) для таких случаев. Хотя это экспериментально, если он когда-либо достигнет принятия стандартов, он может, возможно, положить гвоздь в гроб синхронного запроса.


вы хотели бы проанализировать синхронные вызовы в любом виде обработки, подобной транзакции, или везде, где необходим любой порядок работы.

например, предположим, вы хотите настроить событие, чтобы выйти из системы после воспроизведения песни. Если операция выхода происходит первым, то песня никогда не будет воспроизводиться. Это требует синхронизации запросов.

другая причина была бы при работе с веб-сервисом, особенно при выполнении математики на сервере.

пример: сервер имеет переменную со значением 1.

 Step (1) Perform Update: add 1 to variable
 Step (2) Perform Update: set variable to the power of 3
 End Value: variable equals 8

Если Шаг (2) происходит первым, то конечное значение равно 2, а не 8; таким образом, порядок работы имеет значение и синхронизация необходима.


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

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

вместо синхронных вызовов, однако, часто пользователи хотят остановить событие, которое в настоящее время загружается, а затем выполнить некоторые другие операции. В некотором смысле это синхронизация, так как первое событие завершается до начала второго. Для этого используйте метод abort() для объекта подключения xml.

Я бы сказал, что если вы считаете блокировку браузера пользователя, пока запрос завершается приемлемо, то обязательно используйте синхронный запрос.

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

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

этот фонд идей действительно расширяет ответ vol7ron. Процедуры на основе транзакций-это действительно единственное время, когда должны выполняться синхронные запросы. В большинстве других случаев асинхронные вызовы являются лучшей альтернативой, в которой после вызова DOM обновляется по мере необходимости. Во многих случаях, таких как пользовательские системы, вы можете иметь определенные функции заблокировано для "неавторизованных пользователей", пока они сами не вошли в систему. Эти функции после асинхронного вызова разблокируются с помощью процедуры обновления DOM.

Я должен был бы, наконец, сказать, что я согласен с мнением большинства людей по этому вопросу: везде, где это возможно, следует избегать синхронных запросов XHR, поскольку, как это работает, браузер блокируется синхронными вызовами. При реализации синхронных запросов они должны выполняться таким образом, чтобы браузер обычно был заблокировано, во всяком случае, скажем, в разделе HEAD перед загрузкой страницы на самом деле происходит.

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

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

в одновременном режиме, логика проста, преграждать испытанный потребителем очень короток и никакая проблема.

в асинхронном режиме, пользователь может изменить значения любого другого поля, в то время как начальный проверяется. Эти изменения вызовут другие вызовы xmlhttp со значениями из исходного поля, которые еще не проверены. Что произойдет, если первоначальная проверка не удалась ? Чистый беспорядок. Если режим синхронизации становится устаревшим и запрещенным, логика приложения становится кошмаром для обработки. В основном приложение должно быть переписано для управления блокировками (например. отключите другие элементы во время процессов проверки). Сложность кода значительно возрастает. Невыполнение этого требования может привести к логический сбой и, в конечном счете, повреждение данных.

в основном вопрос заключается в следующем: что важнее, неблокируемый пользовательский интерфейс или риск повреждения данных ? Ответ должен оставаться у разработчика приложения, а не у W3C.

jQuery использует синхронный AJAX внутренне при некоторых обстоятельствах. При вставке HTML, содержащего скрипты, браузер не будет их выполнять. Сценарии должны быть выполнены вручную. Эти сценарии могут присоединять обработчики щелчков. Предположим, что пользователь нажимает на элемент перед подключением обработчика и страница не будет функционировать должным образом. Поэтому, чтобы предотвратить условия гонки, синхронный AJAX будет использоваться для извлечения этих сценариев. Потому что синхронный AJAX эффективно блокирует ко всему прочему, можно быть уверенным, что скрипты и события выполняются в правильном порядке.

с 2015 года настольные приложения javascript становятся все более популярными. Обычно в этих приложениях при загрузке локальных файлов (и загрузка их с помощью XHR является совершенно допустимым вариантом) скорость загрузки настолько высока, что нет смысла усложнять код с помощью асинхронности. Конечно, могут быть случаи, когда асинхронность-это путь (запрос контента из интернета, загрузка действительно больших файлов или огромного количества файлов в одном пакете), но в остальном синхронизация работает просто отлично (и намного проще использовать.)

Что произойдет, если вы сделаете синхронный вызов в производственном коде?

небо падает.

Нет серьезно, пользователь не любит заблокированный браузер.

Я использую его для проверки имени пользователя, во время проверки, что имя пользователя уже не существует.

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

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

иногда у вас есть действие, которое зависит от других. Например, действие B может быть запущено только в том случае, если a завершено. Синхронный подход обычно используется, чтобы избежать гонки. Иногда использование синхронного вызова является более простой реализацией, чем создание сложной логики для проверки каждого состояния ваших асинхронных вызовов, которые зависят друг от друга.

проблема с этим подходом заключается в том, что вы "заблокировать" пользователя браузера до тех пор, пока действие не будет завершено (пока запрос возвращает, заканчивает, загружает и т. д.). Так что будьте осторожны при его использовании.

Я использую синхронные вызовы при разработке кода-все, что вы делали, пока запрос коммутировал на сервер и с сервера, может скрыть причину ошибки.

когда он работает, я делаю его асинхронным, но я пытаюсь включить таймер прерывания и обратные вызовы сбоя, потому что вы никогда не знаете...

причина:

допустим, у вас есть приложение ajax, которое должно сделать полдюжины http-запросов для загрузки различных данных с сервера, прежде чем пользователь сможет выполнить какое-либо взаимодействие.

очевидно, вы хотите, чтобы это срабатывало от onload.

синхронные вызовы работают очень хорошо для этого без каких-либо дополнительных сложностей в коде. Это просто и понятно.

недостаток:

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

альтернатива?

однако многие браузеры блокируют все окна / вкладки, когда в то время как javascript занят в любом из них, что является глупой проблемой дизайна браузера - но в результате блокировка на возможно медленной сети становится не вежливой, если она удерживает пользователей от использования других вкладок во время ожидания для загрузки страницы ajax.

однако, похоже, что синхронные gets были удалены или ограничены из последних браузеров в любом случае. Я не уверен, что это потому, что кто-то решил, что они всегда были плохими, или если авторы браузера были смущены рабочим проектом WC по этой теме.

http://www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/#the-open-method делает его похожим (см. раздел 4.7.3) вы не можете установить тайм-аут при использовании блокировки режим. Мне кажется, что это противоречит интуиции: всякий раз, когда вы блокируете IO, вежливо установить разумный тайм-аут, поэтому зачем разрешать блокировать io, но не с указанным пользователем тайм-аутом?

Я считаю, что блокировка IO имеет жизненно важную роль в некоторых ситуациях, но должна быть реализована правильно. Хотя это не приемлемо для одной вкладки браузера или окна, чтобы заблокировать все другие вкладки или окна, это недостаток дизайна браузера. Стыд там, где должен быть стыд. Но это вполне приемлемо в некоторых случаях для отдельная вкладка или окно не реагируют в течение нескольких секунд (т. е. с помощью блокировки IO/HTTP GET) в некоторых ситуациях-например, при загрузке страницы, возможно, нужно много данных, прежде чем что-либо можно будет сделать в любом случае. Иногда правильно реализованный блокирующий код является самым чистым способом сделать это.

конечно эквивалентная функция в этом случае может быть получена с помощью асинхронного http gets, но какая глупая процедура требуется?

Я думаю, я хотел бы попробовать что-то вдоль этих линий:

при загрузке документа, выполните следующие действия: 1: Настройка 6 глобальных переменных флага "готово", инициализированных до 0. 2: выполнить все 6 фон получает (предполагая, что порядок не имеет значения)

затем обратные вызовы завершения для каждого из 6 HTTP get будут устанавливать свои соответствующие флаги "сделано". Кроме того, каждый обратный вызов будет проверять все другие флаги done, чтобы увидеть, завершены ли все 6 HTTP gets. Последний обратный вызов для завершения, увидев, что все остальные завершены, будет затем вызовите реальную функцию инициализации, которая затем настроит все, теперь, когда все данные были извлечены.

Если порядок выборки имеет значение - или если веб-сервер не может принимать несколько запросов одновременно - то вам понадобится что-то вроде этого:

в onload () будет запущен первый http get. В этом обратном вызове будет запущен второй. В нем обратный вызов, третий - и так далее и так далее, с каждым обратным вызовом, запускающим следующий HTTP ПОЛУЧИТЬ. Когда последний вернется, он вызовет реальную процедуру init ().

XMLHttpRequest традиционно используется для асинхронных запросов. Иногда (для отладки или конкретной бизнес-логики) вы хотели бы изменить все/несколько асинхронных вызовов на одной странице для синхронизации.

Вы хотели бы сделать это без изменения всего в вашем JS-коде. Флаг async/sync дает вам эту возможность, и если он правильно разработан, вам нужно изменить только одну строку в коде / изменить значение one var во время выполнения.

Firefox (и, вероятно, все браузеры, отличные от IE) не поддерживает async xhr timeOut.

  1. обсуждение Stackoverflow
  2. Mozilla Firefox XMLHttpRequest

HTML5 WebWorkers поддерживает тайм-ауты. Так, вы можете хотеть обернуть синхронизации используем XHR-запрос для WebWorker с тайм-аут для реализации асинхронности, как то XHR с поведением тайм-аут.

У меня просто была ситуация, когда асинхронные запросы для списка URL-адресов, вызываемых последовательно с использованием forEach (и цикла for), приводили к отмене оставшихся запросов. Я переключился на синхронный режим, и они работают по назначению.

SYNC vs ASYNC: в чем разница?

в основном это сводится к следующему:

console.info('Hello, World!');
doSomething(function handleResult(result) {
    console.info('Got result!');
});
console.info('Goodbye cruel world!');

, когда doSomething и синхронно это печатать:

Hello, World!
Got result!
Goodbye cruel world!

напротив, если doSomething и асинхронные, это печатать:

Hello, World!
Goodbye cruel world!
Got result!

потому что функция doSomething делает это работа асинхронно, он возвращается, прежде чем это работа делается. Поэтому мы получаем результат только после печати Goodbye cruel world!

если мы зависим от результата вызова asynch, нам нужно поместить зависящий код в обратный вызов:

console.info('Hello, World!');
doSomething(function handleResult(result) {
    console.info('Got result!');
    if (result === 'good') {
        console.info('I feel great!');
    }
    else {
        console.info('Goodbye cruel world!');
    }
});

таким образом, просто тот факт, что 2 или три вещи должны произойти для того, чтобы не было причин делать их синхронно (хотя код синхронизации легче для большинства людей работать).

ЗАЧЕМ ИСПОЛЬЗОВАТЬ СИНХРОННЫЙ XMLHTTPREQUEST?

есть некоторые ситуации, когда вам нужен результат перед вызовом функция завершается. Рассмотрим такой сценарий:

function lives(name) {
    return (name !== 'Elvis');
}
console.info('Elvis ' + (lives('Elvis') ? 'lives!' : 'has left the building...');

предположим, что у нас нет контроля над вызывающим кодом (console.info line) и нужно изменить функцию lives спросить сервер... Мы никак не можем сделать асинхронный запрос на сервер изнутри lives и еще есть наш ответ перед lives завершается. Так что мы не знаем, стоит ли возвращаться true или false. Единственный способ получить результат до завершения функции-это синхронное выполнение запрос.

как Sami Samhuri упоминает в своем ответе, очень реальный сценарий, где вам может понадобиться ответ на ваш запрос сервера, прежде чем ваша функция завершится, - это onbeforeunload событие, так как это последняя функция из вашего приложения, которая будет работать до закрытия окна.

МНЕ НЕ НУЖНО СИНХРОНИЗИРОВАТЬ ВЫЗОВЫ, НО Я ИСПОЛЬЗУЮ ИХ В ЛЮБОМ СЛУЧАЕ, ПОСКОЛЬКУ ОНИ ПРОЩЕ

пожалуйста, не надо. Синхронные вызовы запереть Ваш браузер и сделать приложение чувствовать себя не отвечает. Но вы правы. Асинхронный код сложнее. Однако есть способ сделать работу с ним намного проще. Не так просто, как синхронизировать код, но он приближается:обещание s.

вот пример: два вызова asynch должны завершиться успешно, прежде чем третий сегмент кода может выполняться:

var carRented = rentCar().then(function(car){
  gasStation.refuel(car);
});

var hotelBooked = bookHotel().then(function(reservation) {
  reservation.confirm();
});

Promise.all([carRented, hotelBooked]).then(function(){
  // At this point our car is rented and our hotel booked.
  goOnHoliday();
});

вот как бы вы реализовали bookHotel:

function bookHotel() {
  return new Promise(function(resolve, reject){
    if (roomsAvailable()) {
      var reservation = reserveRoom();
      resolve(reservation);
    }
    else {
      reject(new Error('Could not book a reservation. No rooms available.'));
    }
  });
}

Читайте также: написать лучше JavaScript с обещаниями.

Ну вот одна веская причина. Я хотел сделать http-запрос, а затем, в зависимости от результата, вызвать click() на входном типе=file. Это невозможно с асинхронным xhr или fetch. Обратный вызов теряет контекст "действие пользователя", поэтому вызов click() игнорируется. Синхронный xhr спас мой бекон.

onclick(event){
    //here I can, but I don't want to.
    //document.getElementById("myFileInput").click();
    fetch("Validate.aspx", { method : "POST", body: formData, credentials: "include" })
    .then((response)=>response.json())
    .then(function (validResult) {
        if (validResult.success) {
            //here, I can't.
            document.getElementById("myFileInput").click();
        }
    });
}