Здається, більшість усіх робить асинхронні запити за допомогою XMLHttpRequest, але очевидно той факт, що є можливість робити синхронні запити, вказує на те, що для цього може бути вагома причина. То яка може бути ця поважна причина?
Здається, більшість усіх робить асинхронні запити за допомогою XMLHttpRequest, але очевидно той факт, що є можливість робити синхронні запити, вказує на те, що для цього може бути вагома причина. То яка може бути ця поважна причина?
Відповіді:
Я думаю, що вони можуть стати більш популярними в міру просування стандартів HTML 5. Якщо веб-програма отримає доступ до веб-співробітників, я міг би передбачити розробників, які використовують спеціального веб-працівника для надсилання синхронних запитів, як сказав Джонатан, для забезпечення одного запиту перед іншим. У поточній ситуації з одним потоком це менш ідеальний дизайн, оскільки він блокується до завершення запиту.
Синхронні XHR корисні для збереження даних користувачів. Якщо ви обробляєте beforeunload
подію, ви можете завантажувати дані на сервер, коли користувач закриває сторінку.
Якби це було зроблено за допомогою опції асинхронізації, сторінка могла б закритися до завершення запиту. Виконання цього синхронно гарантує, що запит завершиться або не виконається очікуваним чином.
Нижче натякнуто - але йому не вдалося доставити - що з появою кращої асинхронної обробки запитів дійсно немає причин використовувати синхронні запити, якщо тільки не мають наміру спеціально блокувати користувачів робити що-небудь, доки запит не буде завершено - звучить шкідливо: )
Хоча це може звучати погано, можуть бути випадки, коли важливо, щоб запит (або серія запитів) відбувся до того, як користувач покине сторінку або до того, як буде виконана дія - блокування виконання іншого коду (наприклад, запобігання кнопці "Назад") може можливо, зменшити кількість помилок / обслуговування для погано розробленої системи; тим не менш, я ніколи не бачив цього в дикій природі і наголошую, що цього слід уникати.
Бібліотеки, як обіцянки , прикидаються синхронністю, зв’язуючи процеси за допомогою зворотних дзвінків. Це підходить для більшості потреб у розробці, де прагненням є замовлені, неблокуючі події, які дозволяють браузерам зберігати чуйність для користувача (хороший UX).
Як зазначено в документах Mozilla, бувають випадки, коли вам доводиться використовувати синхронні запити; однак також перелічено обхідний шлях, який використовує маяк (недоступний в IE / Safari) для таких випадків. Хоча це експериментально, якщо воно коли-небудь досягне прийняття стандартів, воно, можливо, може забити цвях у труну із синхронним запитом.
Ви хочете виконувати синхронні дзвінки в будь-якій транзакційній обробці або там, де необхідний будь-який порядок операцій.
Наприклад, припустимо, ви хочете налаштувати подію, щоб вийти з системи після відтворення пісні. Якщо операція виходу виконується спочатку, пісня ніколи не буде відтворена. Для цього потрібна синхронізація запитів.
Іншою причиною може бути робота з WebService, особливо при математиці на сервері.
Приклад: Сервер має змінну зі значенням 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 попереднього запиту запускає наступний у черзі.
Є багато справжніх випадків, коли блокування користувацького інтерфейсу є саме бажаною поведінкою.
Візьміть програму з кількома полями, і деякі поля повинні бути перевірені за допомогою виклику xmlhttp на віддалений сервер, надаючи як вхідні дані значення цього поля та інші значення полів.
У синхронному режимі логіка проста, блокування користувачем дуже коротке, і проблем немає.
В асинхронному режимі користувач може змінювати значення будь-яких інших полів, поки перевіряється початкове. Ці зміни спричинять інші виклики xmlhttp зі значеннями з початкового поля, які ще не перевірені. Що станеться, якщо початкова перевірка не вдалася? Чистий безлад. Якщо режим синхронізації стає застарілим і забороненим, логіка програми стає кошмаром, з яким потрібно обробляти. В основному програма повинна бути переписана для управління блокуваннями (наприклад, вимкнути інші елементи під час процесів перевірки). Складність коду надзвичайно зростає. Якщо цього не зробити, це може призвести до збою в логіці та, зрештою, до пошкодження даних.
В основному питання полягає в тому: що важливіше, незаблокований досвід користувальницького інтерфейсу чи ризик пошкодження даних? Відповідь повинен залишатися у розробника додатка, а не у W3C.
Я бачу використання синхронних запитів XHR, які слід використовувати, коли ресурс у змінному розташуванні повинен бути завантажений перед іншими статичними ресурсами на сторінці, які залежать від першого ресурсу, щоб повністю функціонувати. Насправді, я реалізую такий запит XHR у власному невеликому підпроекті, тоді як ресурси JavaScript перебувають у змінних місцях на сервері в залежності від набору конкретних параметрів. Подальші ресурси JavaScript покладаються на ці змінні ресурси, і такі файли ПОВИННІ гарантовано завантажуватися до завантаження інших надійних файлів, що робить додаток цілим.
Цей підґрунтя ідеї справді розширюється щодо відповіді vol7ron. Процедури на основі транзакцій - це справді єдиний час, коли слід робити синхронні запити. У більшості інших випадків асинхронні дзвінки є кращою альтернативою, коли після виклику DOM оновлюється за необхідності. У багатьох випадках, наприклад, на базі користувачів, певні функції можуть бути заблоковані для "неавторизованих користувачів", поки вони самі по собі не ввійдуть в систему. Ці функції після асинхронного дзвінка розблоковуються за допомогою процедури оновлення DOM.
Нарешті, мені доведеться сказати, що я погоджуюся з думками більшості людей щодо цього питання: скрізь, де можливо, слід уникати синхронних запитів XHR, оскільки, як це працює, браузер блокує синхронні дзвінки. Під час реалізації синхронних запитів їх слід робити таким чином, щоб браузер, як правило, був заблокований, у будь-якому випадку, скажімо в розділі HEAD перед тим, як насправді відбудеться завантаження сторінки.
Починаючи з 2015 року програми для настільних комп'ютерів JavaScript стають все більш популярними. Зазвичай у цих програмах під час завантаження локальних файлів (і завантаження їх за допомогою XHR є цілком допустимим варіантом) швидкість завантаження настільки висока, що мало сенсу переускладнювати код за допомогою асинхронізації. Звичайно, можуть бути випадки, коли асинхронізація - це шлях (запит вмісту з Інтернету, завантаження дійсно великих файлів або величезна кількість файлів в одній партії), але в іншому випадку синхронізація працює чудово (і набагато простіша у використанні) .
jQuery використовує синхронний AJAX внутрішньо за певних обставин. При вставці HTML, що містить сценарії, браузер не виконуватиме їх. Сценарії потрібно виконувати вручну. Ці скрипти можуть додавати обробники клацань. Припустимо, що користувач натискає елемент до того, як обробник приєднаний, і сторінка не буде функціонувати належним чином. Тому для запобігання гоночним умовам для отримання цих скриптів буде використовуватися синхронний AJAX. Оскільки синхронний AJAX ефективно блокує все інше, можна бути впевненим, що сценарії та події виконуються у правильному порядку.
Причина:
Скажімо, у вас є програма ajax, якій потрібно виконати півдюжини http, щоб завантажити різні дані із сервера, перш ніж користувач зможе здійснити будь-яку взаємодію.
Очевидно, ви хочете, щоб це спрацьовувало від onload.
Синхронні дзвінки дуже добре працюють для цього без додаткової складності коду. Це просто і просто.
Недолік:
Єдиним недоліком є те, що ваш браузер блокується, поки не завантажаться всі дані або не закінчиться час очікування. Що стосується програми ajax, про яку йде мова, це не становить великих проблем, оскільки програма не корисна, доки всі вихідні дані все одно не будуть завантажені.
Альтернатива?
Однак багато браузерів блокують всі вікна / вкладки, коли, поки javascript зайнятий в будь-якому з них, що є дурною проблемою дизайну браузера, але в результаті блокування можливо повільної мережі не є ввічливим, якщо заважає користувачам використовувати інші вкладки в очікуванні завантаження сторінки ajax.
Однак схоже на те, що синхронні отримання все одно були вилучені або обмежені з останніх браузерів. Я не впевнений, що це тому, що хтось вирішив, що вони завжди завжди погані, чи розробників браузера бентежить робочий проект WC на цю тему.
http://www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/#the-open-method виглядає так (див. розділ 4.7.3), що ви не можете встановлювати час очікування під час використання режиму блокування . Мені здається протилежним інтуїтивно зрозумілим: всякий раз, коли хтось робить блокування вводу-виводу, ввічливо встановлювати розумний тайм-аут, то чому навіщо дозволяти блокування io, але не за вказаним користувачем тайм-аутом?
На мою думку, блокування введення-виведення відіграє життєво важливу роль у деяких ситуаціях, але його слід правильно застосовувати. Хоча для однієї вкладки або вікна браузера не прийнятно блокувати всі інші вкладки чи вікна, це недолік дизайну браузера. Ганьба там, де сором. Але цілком прийнятно в деяких випадках, коли окрема вкладка чи вікно не реагує на кілька секунд (тобто з використанням блокування IO / HTTP GET) у деяких ситуаціях - наприклад, при завантаженні сторінки, можливо, багато даних має бути перед тим, як щось можна зробити в будь-якому випадку. Іноді правильно реалізований код блокування - це найчистіший спосіб це зробити.
Звичайно, еквівалентну функцію в цьому випадку можна отримати, використовуючи асинхронний http отримує, але який тип шаленої рутини потрібно?
Думаю, я спробував би щось подібне:
Під час завантаження документа виконайте наступне: 1: Налаштуйте 6 глобальних змінних прапора "Готово", ініціалізовані до 0. 2: Виконайте всі 6 фонових одержень (припускаючи, що порядок не має значення)
Потім, зворотні виклики завершення для кожного з 6 http-отримувань встановлюватимуть відповідні прапори "Готово". Крім того, кожен зворотний виклик перевіряв би всі інші виконані прапори, щоб перевірити, чи всі 6 HTTP-одержень завершені. Останній зворотний виклик, який завершився, побачивши, що всі інші завершили, потім викличе функцію REAL init, яка потім налаштує все, тепер, коли всі дані отримані.
Якщо порядок вибору мав значення - або якщо веб-сервер не зміг прийняти кілька запитів одночасно - тоді вам знадобиться щось подібне:
У onload () буде запущено перший http get. У цьому випадку буде запущений другий. У цьому зворотний виклик, третій - і так далі, і так далі, з кожним зворотним викликом запускається наступний HTTP GET. Коли повернувся останній, це викликало б справжню процедуру init ().
Що станеться, якщо ви зробите синхронний виклик у виробничому коді?
Небо падає вниз.
Несерйозно, користувачеві не подобається заблокований браузер.
Я використовую його для перевірки імені користувача під час перевірки, що ім’я користувача ще не існує.
Я знаю, що було б краще зробити це асинхронно, але тоді я повинен використовувати інший код для цього конкретного правила перевірки. Я пояснюю краще. Моє налаштування перевірки використовує деякі функції перевірки, які повертають true або false, залежно від того, чи дані є дійсними.
Оскільки функція повинна повернутися, я не можу використовувати асинхронні методи, тому я просто роблю це синхронно і сподіваюся, що сервер відповість досить швидко, щоб не бути занадто помітним. Якби я використовував зворотний виклик AJAX, то мені довелося б обробляти решту виконання інакше, ніж інші методи перевірки.
false
) і просто встановити для нього значення true або false, коли сервер відповідає. при зміні поля ви скидаєте прапор і знову викликаєте сервер.
Іноді у вас є дія, яка залежить від інших. Наприклад, дію B можна розпочати, лише якщо A закінчено. Синхронний підхід зазвичай використовується, щоб уникнути перегонових умов . Іноді використання синхронного виклику є більш простою реалізацією, ніж створення складної логіки для перевірки кожного стану ваших асинхронних викликів, які залежать один від одного.
Проблема цього підходу полягає в тому, що ви "блокуєте" браузер користувача, поки дія не буде закінчена (доки запит не повернеться, не завершиться, не завантажиться тощо). Тому будьте обережні, використовуючи його.
Я використовую синхронні дзвінки під час розробки коду - все, що ви робили, коли запит їздив до сервера та з сервера, може затемнити причину помилки.
Коли він працює, я роблю його асинхронним, але намагаюся включити таймер переривання та зворотних викликів, оскільки ви ніколи не знаєте ...
SYNC проти 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!
Якщо ми залежамо від результату асинхронного виклику, нам потрібно помістити відповідний код у зворотний виклик:
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 або 3 речі, не є підставою робити їх синхронно (хоча для коду синхронізації більшість людей простіше працювати).
ЧОМУ ВИКОРИСТОВАТИ СИНХРОННИЙ XMLHTTPREQUEST?
Є деякі ситуації, коли вам потрібен результат до завершення викликаної функції. Розглянемо такий сценарій:
function lives(name) {
return (name !== 'Elvis');
}
console.info('Elvis ' + (lives('Elvis') ? 'lives!' : 'has left the building...');
Припустимо, ми не маємо контролю над викличним кодом ( console.info
лінією) і нам потрібно змінити функцію, lives
щоб запитати сервер ... Ми жодним чином не можемо зробити запит асинхронізації до сервера зсередини lives
і все одно матимемо свою відповідь до lives
завершення. Тож ми не знали, повертатись true
чиfalse
. Єдиний спосіб отримати результат до завершення функції - це зробити синхронний запит.
Як Sami Samhuri
згадується у його відповіді, цілком реальним сценарієм, коли вам може знадобитися відповідь на запит сервера до завершення роботи вашої функції, є onbeforeunload
подія, оскільки це остання функція з вашої програми, яка коли-небудь працювала до закриття вікна.
Мені НЕ ПОТРІБНІ СИНХРОНІЗАЦІЇ, АЛЕ ВСЕ ВИКОРИСТОВУЮТЬ їх, оскільки вони простіші
Будь ласка, не роби. Синхронні дзвінки блокують ваш браузер і змушують програму не реагувати. Але ти маєш рацію. Асинхронний код складніше. Однак є спосіб набагато полегшити боротьбу з цим. Це не так просто, як код синхронізації, але він наближається: Promise s.
Ось приклад: Два асинхронних виклики повинні успішно завершитися до того, як може запуститися третій сегмент коду:
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 із обіцянками .
XMLHttpRequest
традиційно використовується для асинхронних запитів. Іноді (для налагодження або конкретної бізнес-логіки) ви хотіли б змінити всі / кілька асинхронних викликів на одній сторінці для синхронізації.
Ви хотіли б це зробити, не змінюючи все у своєму коді JS. Прапор асинхронізації / синхронізації дає вам таку можливість, і якщо правильно розроблено, вам потрібно змінити лише один рядок у коді / змінити значення одного var
під час виконання.
Firefox (і, ймовірно, всі браузери, що не належать до IE) не підтримує асинхронний XHR timeOut.
HTML5 WebWorkers підтримують таймаути. Отже, можливо, ви захочете обернути запит синхронізації XHR до WebWorker з часом очікування, щоб реалізувати асинхронний XHR із поведінкою часу очікування.
У мене щойно виникла ситуація, коли асинхронні запити на список URL-адрес, викликаних послідовно, використовуючи forEach (і цикл for), спричинять скасування решти запитів. Я перейшов на синхронний, і вони працюють за призначенням.
Використання синхронних HTTP-запитів є звичайною практикою в бізнесі мобільної реклами.
Компанії (вони ж "Видавці"), які створюють додатки, часто показують рекламу для отримання доходу. Для цього вони встановлюють рекламні SDK у свій додаток. Багато існує (MoPub, Ogury, TapJob, AppNext, Google Ads AdMob).
Ці пакети SDK відображатимуть рекламу під час веб-перегляду.
Показуючи рекламу користувачеві, це має бути зручним способом , особливо під час відтворення відео. Будь-якої миті не повинно бути буферизації або завантаження.
Для вирішення цього precaching
використовується. Де засоби масової інформації (зображення / відео / тощо) завантажуються синхронно у фоновому режимі веб-перегляду.
Чому б не зробити це асинхронно?
onload
подію, щоб дізнатись, коли реклама "готова" для показу користувачевіІз припиненням синхронних запитів XMLHttpRequests , рекламний бізнес, швидше за все, буде змушений змінити стандарт у майбутньому, якщо не вдасться визначити інший спосіб.
Синхронний XHR може бути дуже корисним для (невиробничого) внутрішнього розробки інструментів та / або фреймворку. Уявіть, наприклад, ви хотіли завантажити бібліотеку коду синхронно при першому доступі, наприклад:
get draw()
{
if (!_draw)
{
let file;
switch(config.option)
{
case 'svg':
file = 'svgdraw.js';
break;
case 'canvas':
file = 'canvasdraw.js';
break;
default:
file = 'webgldraw.js';
}
var request = new XMLHttpRequest();
request.open('GET', file, false);
request.send(null);
_draw = eval(request.responseText);
}
return _draw;
}
Перш ніж потрапити в запаморочення і сліпо відрегулювати зло евалу, майте на увазі, що це лише для місцевого тестування. Для виробничих збірок буде вже встановлено _draw.
Отже, ваш код може виглядати так:
foo.drawLib.draw.something(); //loaded on demand
Це лише один приклад того, що було б неможливо зробити без синхронізації XHR. Ви можете завантажити цю бібліотеку заздалегідь, так, або зробити обіцянку / зворотний виклик, але ви не можете завантажити lib синхронно без синхронізації XHR. Подумайте, наскільки такий тип речей може очистити ваш код ...
Обмеження того, що ви можете зробити з цим для інструментів та фреймворків (які працюють локально), обмежені лише вашою уявою. Хоча, здається, уява трохи обмежена у світі JavaScript.
Ну ось одна вагома причина. Я хотів зробити http-запит, після чого, залежно від результату, викликати click () на тип вводу = файл. Це неможливо з асинхронним 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();
}
});
}