У меня есть виджет JavaScript, который предоставляет стандартные точки расширения. Одна из них - это функция beforecreate
. Он должен возвращать false
чтобы предотвратить создание элемента.
Я добавил вызов Ajax в эту функцию, используя jQuery:
beforecreate: function (node, targetNode, type, to) {
jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),
function (result) {
if (result.isOk == false)
alert(result.message);
});
}
Но я хочу, чтобы мой виджет не создавал этот элемент, поэтому я должен возвращать false
в функции mother, а не в обратном вызове. Есть ли способ выполнить синхронный запрос AJAX с использованием jQuery или любого другого API-интерфейса в браузере?
Из документации jQuery: вы указываете опцию асинхронная как false, чтобы получить синхронный запрос Ajax. Тогда ваш обратный вызов может установить некоторые данные до того, как ваша материнская функция продолжит.
Вот как выглядел бы ваш код, если бы он был изменен, как было предложено:
beforecreate: function (node, targetNode, type, to) {
jQuery.ajax({
url: 'http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value),
success: function (result) {
if (result.isOk == false) alert(result.message);
},
async: false
});
}
Вы можете установить jQuery Ajax в синхронном режиме, позвонив
jQuery.ajaxSetup({async:false});
Затем выполните ваши вызовы Ajax с помощью jQuery.get(... );
Затем просто включайте его снова
jQuery.ajaxSetup({async:true});
Я предполагаю, что это работает так же, как предложено @Adam, но может быть полезно кому-то, кто хочет перенастроить свои jQuery.get()
или jQuery.post()
в более сложный синтаксис jQuery.ajax()
.
$.ajax()
КРОМЕ $.ajax()
». ;)
Отличное решение! Я заметил, что когда я попытался реализовать его, если бы я вернул значение в предложение success, оно вернулось как неопределенное. Мне пришлось хранить его в переменной и возвращать эту переменную. Это метод, который я придумал:
function getWhatever() {
// strUrl is whatever URL you need to call
var strUrl = "", strReturn = "";
jQuery.ajax({
url: strUrl,
success: function(html) {
strReturn = html;
},
async:false
});
return strReturn;
}
getWhatever
. Таким образом, вы ничего не вернули, т.е. undefined
из вашего getWhatever
.
Все эти ответы не согласны с тем, что выполнение Ajax-вызова с помощью async: false приведет к зависанию браузера, пока не будет завершен запрос Ajax. Использование библиотеки управления потоками позволит решить эту проблему, не повесив браузер. Ниже приведен пример с Frame.js:
beforecreate: function(node,targetNode,type,to) {
Frame(function(next)){
jQuery.get('http://example.com/catalog/create/', next);
});
Frame(function(next, response)){
alert(response);
next();
});
Frame.init();
}
function getURL(url){
return $.ajax({
type: "GET",
url: url,
cache: false,
async: false
}).responseText;
}
//example use
var msg=getURL("message.php");
alert(msg);
Имейте в виду, что если вы выполняете междоменный вызов Ajax (используя JSONP) - вы не можете делать он синхронно, флаг async
будет игнорироваться jQuery.
$.ajax({
url: "testserver.php",
dataType: 'jsonp', // jsonp
async: false //IGNORED!!
});
Для JSONP-вызовов вы можете использовать:
Примечание. Вы не должны использовать async из-за этого:
Начиная с Gecko 30.0 (Firefox 30.0/Thunderbird 30.0/SeaMonkey 2.27), синхронные запросы в основном потоке устарели из-за негативных последствий для пользователя.
Chrome даже предупреждает об этом в консоли:
Синхронный XMLHttpRequest в основном потоке устарел из-за его пагубных последствий для конечного пользователя. Для получения дополнительной справки проверьте https://xhr.spec.whatwg.org/.
Это может сломать вашу страницу, если вы делаете что-то подобное, так как она может перестать работать в любой день.
Если вы хотите сделать это так, как будто это синхронно, но все равно не блокировать, вы должны использовать async/wait и, возможно, также ajax, основанный на обещаниях, таких как новый API Fetch
async function foo() {
var res = await fetch(url)
console.log(res.ok)
var json = await res.json()
console.log(json)
}
await fetch(url)
в блок try... catch
чтобы перехватить любые асинхронные ошибки.
async
, поэтому вы можете просто выполнить foo().catch(...)
чтобы перехватить его
Я использовал ответ, данный Carcione, и изменил его, чтобы использовать JSON.
function getUrlJsonSync(url){
var jqxhr = $.ajax({
type: "GET",
url: url,
dataType: 'json',
cache: false,
async: false
});
// 'async' has to be 'false' for this to work
var response = {valid: jqxhr.statusText, data: jqxhr.responseJSON};
return response;
}
function testGetUrlJsonSync()
{
var reply = getUrlJsonSync("myurl");
if (reply.valid == 'OK')
{
console.dir(reply.data);
}
else
{
alert('not valid');
}
}
Я добавил dataType 'JSON' и изменил .responseText на responseJSON.
Я также получил статус с использованием свойства statusText возвращаемого объекта. Обратите внимание, что это статус ответа Ajax, а не действителен ли JSON.
Внутренний сервер должен вернуть ответ в правильном (правильно сформированном) JSON, иначе возвращаемый объект будет неопределенным.
При ответе на исходный вопрос необходимо учитывать два аспекта. Один говорит Ajax выполнять синхронно (путем установки async: false), а другой возвращает ответ через оператор возврата функции вызова, а не в функцию обратного вызова.
Я также пробовал его с помощью POST, и он работал.
Я изменил GET на POST и добавил данные: postdata
function postUrlJsonSync(url, postdata){
var jqxhr = $.ajax({
type: "POST",
url: url,
data: postdata,
dataType: 'json',
cache: false,
async: false
});
// 'async' has to be 'false' for this to work
var response = {valid: jqxhr.statusText, data: jqxhr.responseJSON};
return response;
}
Обратите внимание, что приведенный выше код работает только в случае, когда async является ложным. Если вы должны были установить async: true, возвращаемый объект jqxhr недействителен во время вызова AJAX, только позже, когда асинхронный вызов будет завершен, но слишком поздно установить переменную ответа.
С async: false
вы получаете заблокированный браузер.
Для неблокирующего синхронного решения вы можете использовать следующее:
С ES6 вы можете использовать генератор и co library:
beforecreate: function (node, targetNode, type, to) {
co(function*(){
let result = yield jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
//Just use the result here
});
}
С ES7 вы можете просто использовать asyc wait:
beforecreate: function (node, targetNode, type, to) {
(async function(){
let result = await jQuery.get('http://example.com/catalog/create/' + targetNode.id + '?name=' + encode(to.inp[0].value));
//Just use the result here
})();
}
async function
в beforecreate beforecreate: async function(....
и удалить вызываемую асинхронную функцию самостоятельно
Это пример:
$.ajax({
url: "test.html",
async: false
}).done(function(data) {
// Todo something..
}).fail(function(xhr) {
// Todo something..
});
async false
с решением на основе обещаний. Это только блокирует браузер без какой-либо выгоды.
function isValidLogin() {
var flag = false;
var Response = $.ajax({
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: "UPSLabelFormCA.aspx/IsValidLogin",
async: false
}).responseText;
var toJson = jQuery.parseJSON(Response);
if (toJson.d[0].Message == 'SUCCESS') {
flag = true;
}
return flag;
}
[WebMethod]
public static List<ShipInfo> IsValidLogin()
{
List<ShipInfo> loginStatus = new List<ShipInfo>();
if (HttpContext.Current.User.Identity.IsAuthenticated && HttpContext.Current.Session["Email"] != null)
{
loginStatus.Add(new ShipInfo() { Success = true, Message = "SUCCESS" });
}
else
{
loginStatus.Add(new ShipInfo() { Success = false, Message = "FAILED" });
}
return loginStatus;
}
Во-первых, мы должны понимать, когда мы используем $.ajax и когда мы используем $.get/$. post
Когда мы требуем низкого уровня контроля над запросом ajax, таким как настройки заголовка запроса, настройки кеширования, синхронные настройки и т.д., тогда мы должны пойти на $.ajax.
$. get/$. post: Когда мы не требуем низкого уровня контроля над ajax-запросом. Просто просто получайте/отправляйте данные на сервер. Это сокращение
$.ajax({
url: url,
data: data,
success: success,
dataType: dataType
});
и, следовательно, мы не можем использовать другие функции (синхронизация, кеш и т.д.) с помощью $.get/$. post.
Следовательно, для управления низким уровнем (синхронизация, кеш и т.д.) по запросу ajax мы должны перейти на $.ajax
$.ajax({
type: 'GET',
url: url,
data: data,
success: success,
dataType: dataType,
async:false
});
Поскольку синхронная операция XMLHttpReponse
устарела, я придумал следующее решение, которое обертывает XMLHttpRequest
. Это позволяет заказывать запросы AJAX, сохраняя при этом асинхронный характер, что очень полезно для одноразовых токенов CSRF.
Он также прозрачен, поэтому библиотеки, такие как jQuery, будут работать без сбоев.
/* wrap XMLHttpRequest for synchronous operation */
var XHRQueue = [];
var _XMLHttpRequest = XMLHttpRequest;
XMLHttpRequest = function()
{
var xhr = new _XMLHttpRequest();
var _send = xhr.send;
xhr.send = function()
{
/* queue the request, and if it the first, process it */
XHRQueue.push([this, arguments]);
if (XHRQueue.length == 1)
this.processQueue();
};
xhr.processQueue = function()
{
var call = XHRQueue[0];
var xhr = call[0];
var args = call[1];
/* you could also set a CSRF token header here */
/* send the request */
_send.apply(xhr, args);
};
xhr.addEventListener('load', function(e)
{
/* you could also retrieve a CSRF token header here */
/* remove the completed request and if there is more, trigger the next */
XHRQueue.shift();
if (XHRQueue.length)
this.processQueue();
});
return xhr;
};
это моя простая реализация для запросов ASYNC с помощью jQuery. Надеюсь, это поможет кому угодно.
var queueUrlsForRemove = [
'http://dev-myurl.com/image/1',
'http://dev-myurl.com/image/2',
'http://dev-myurl.com/image/3',
];
var queueImagesDelete = function(){
deleteImage( queueUrlsForRemove.splice(0,1), function(){
if (queueUrlsForRemove.length > 0) {
queueImagesDelete();
}
});
}
var deleteImage = function(url, callback) {
$.ajax({
url: url,
method: 'DELETE'
}).done(function(response){
typeof(callback) == 'function' ? callback(response) : null;
});
}
queueImagesDelete();
beforecreate
.