2013-07-22 3 views
3

Есть ли способ выполнить синхронный запрос AJAX, который не блокирует браузер? На мой взгляд, синхронные запросы в большинстве случаев намного легче работать, но тот факт, что они блокируют выполнение других частей кода, является настоящим убийцей. Есть ли способ получить синхронный AJAX без отрицательных побочных эффектов? (И да, я понимаю, что термин «Синхронный AJAX» является оксюмороном.)Неблокирующий синхронный AJAX

+4

Я так не думаю ... Предлагаю вам узнать о обещаниях, облегчить работу с AJAX. – elclanrs

+0

@hexacyanide Извините, я думаю, это было плохо сформулировано. Я имею в виду, что он не замораживает браузер или блокирует другие события в моем коде от запуска. – Ajedi32

+0

Даже если «неблокирующее синхронное» не было противоречием, это невозможно для такой конструкции в однопотоковой (однопоточной) среде. Альтернативой и, действительно, решением в браузере JavaScript является «неблокирующее * асинхронное». – user2246674

ответ

2

Я приведу пример плохой стороны воздействия такого поведения.

Допустим, у вас есть эта программа:

<script> 
var file = "foo.json"; 

function nullIt() { 
    file = null; 
} 

function loadFile() { 
    if (file != null) { 
     synchronousLoad(file);//imagine the load takes 5 seconds 
     alert("i just loaded: " + file); 
    } 
} 

window.onload = loadFile; 
</script> 
<button onclick="nullIt()">click me</button> 

Плохая вещь здесь-

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

Настоящая проблема здесь вы больше не можете рассуждать о своем коде. Просто потому, что какой-то факт был true в строке 5, не означает, что он по-прежнему верен на самой следующей строке. Это затрудняет запись бесплатной программы.

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

Сравнительно говоря, использование обратных вызовов для выполнения асинхронных операций - это ez-режим.

+1

Ах, отличная точка. Лично я бы предпочел рискнуть с такими «условиями гонки» (если можно так выразиться), но приятно видеть какое-то оправдание, почему все так, как есть. – Ajedi32

3

№ Синхронный по определению блокирует. Ничто не может продолжаться до тех пор, пока процесс не завершится. Это включает в себя остальную часть пользовательского интерфейса в веб-браузере.

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

1

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

Пример использования jQuery.ajax()

jQuery.ajax({ 
    url: "URL HERE", 
    data: "whatever you are sending" 
}).done(function (data) { 
    // Do things with data 
}); 

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

+0

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

+0

@ Ajedi32 Это совсем не чище - в частности, потому что он * не работает * с одним контекстом выполнения, например, используемым браузером JavaScript. Кроме того, когда используются несколько контекстов выполнения (т. Е. Потоки или даже продолжения), есть дополнительные соображения и проблемы, связанные с: неявное атомное исполнение удаляется, и [другие формы] условий гонки должны быть защищены. – user2246674

+1

@ Ajedi32 Используя обещания (в частности, 'then', реализованные в jQuery 1.8+ и кодированные [Promises/A] (http://wiki.commonjs.org/wiki/Promises/A)), могут значительно очистить асинхронный код Применение. Я считаю, что эта модель обещаний намного более последовательна и чиста для решения, чем предыдущие обратные вызовы/ошибки. – user2246674

0

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

Однако, если сложность кода является основной причиной нежелания асинхронных вызовов методов, вам может быть интересен кросс-компилятор Javascript streamline.js, который позволяет вам писать асинхронные вызовы методов, как если бы они были синхронными, и получить такой же результат, как если бы вы написали вызов асинхронно.

С GitHub страницы проекта:

streamline.js является инструментом языка для упрощения асинхронного Javascript программирования.

Вместо того чтобы писать код волосатые, как:

function archiveOrders(date, cb) { 
    db.connect(function(err, conn) { 
    if (err) return cb(err); 
    conn.query("select * from orders where date < ?", [date], function(err, orders) { 
     if (err) return cb(err); 
     helper.each(orders, function(order, next) { 
     conn.execute("insert into archivedOrders ...", [order.id, ...], function(err) { 
      if (err) return cb(err); 
      conn.execute("delete from orders where id=?", [order.id], function(err) { 
      if (err) return cb(err); 
      next(); 
      }); 
     }); 
     }, function() { 
     console.log("orders have been archived"); 
     cb(); 
     }); 
    }); 
    }); 
} 

Вы пишете:

function archiveOrders(date, _) { 
    var conn = db.connect(_); 
    conn.query("select * from orders where date < ?", [date], _).forEach_(_, function(_, order) { 
    conn.execute("insert into archivedOrders ...", [order.id, ...], _); 
    conn.execute("delete from orders where id=?", [order.id], _); 
    }); 
    console.log("orders have been archived"); 
} 

и обтекаемый преобразует код и заботится о обратных вызовов!

Нет API-интерфейсов управления доступом, чтобы узнать! Вы просто должны следовать простому правилу:

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

Для получения дополнительной информации о streamline.js, читайте в нашем блоге Asynchronous Javascript – the tale of Harry.

1

В новом стандарте ECMAScript 2016 (ES7) есть новый набор языковых ключевых слов, предназначенный для выполнения чего-то очень похожего на то, что вы, похоже, ищете, называется async и await.

Эти ключевые слова не позволяют «неблокирующая синхронную AJAX», но они не позволяют писать асинхронный код таким образом, что выглядит синхронными. Вот простой пример:

// Let's say you have an asynchronous function that you want to call in a synchronous 
// style... 
function delayedEval(delay, func) { 
    // First, ensure that the function returns a Promise object. If it doesn't, wrap it with 
    // another function that does. 
    return new Promise((resolve, reject) => { 
    setTimeout(() => resolve(func()), delay) 
    }) 
    // For more on Promises, see https://goo.gl/uaoDuy (MDN link) 
} 

// Then, declare a function as asynchronous. This causes it to return a Promise that 
// resolves to its return value, instead of returning its return value directly. 
async function delayedHello() { 
    // Inside an async function, you can call other async functions like this, which looks 
    // very much like a synchronous call (even though it isn't). 
    let message = await delayedEval(1500,() => "Hello, world!") 
    console.log(message) 
} 

// This returns (a Promise) immediately, but doesn't print "Hello, world!" until 1.5 
// seconds later. (At which point it resolves the Promise.) 
delayedHello() 

Try in Babel

В принципе, вместо «синхронизирован AJAX без негативных побочных эффектов», async и await получить вам асинхронный AJAX без всех его негативных побочных эффектов. (Мессиальный код с большим количеством логики для обработки обратных вызовов.)

async и await являются частью "async functions" candidate recommendation в стандарте ES7.

Смежные вопросы