如何让jQuery执行同步而非异步的Ajax请求?
-
02-07-2019 - |
题
我有一个JavaScript小部件,它提供标准的扩展点。其中之一是 beforecreate
函数。它应返回 false
以防止创建项目。
我使用jQuery在这个函数中添加了一个Ajax调用:
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
,而不是在回调中。有没有办法使用jQuery或任何其他浏览器中的API执行同步AJAX请求?
解决方案
从 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});
然后使用 jQuery.get(...);
然后再打开一次
jQuery.ajaxSetup({async:true});
我想这与@Adam建议的相同,但对于想要重新配置 jQuery.get()
或 jQuery.post的人来说,它可能会有所帮助。 )
更精细的 jQuery.ajax()
语法。
出色的解决方案!我注意到当我尝试实现它时,如果我在success子句中返回一个值,那么它返回为undefined。我必须将它存储在变量中并返回该变量。这是我提出的方法:
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;
}
所有这些答案都错过了使用async执行Ajax调用的错误: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);
注意:由于此警告消息,您不应使用 async:false
:
从Gecko 30.0(Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27)开始,由于对用户体验的负面影响,主线程上的同步请求已被弃用。
Chrome甚至在控制台中发出警告:
主线程上的同步XMLHttpRequest因其对最终用户体验的不利影响而被弃用。如需更多帮助,请查看 https://xhr.spec.whatwg.org/ 。
如果您正在做这样的事情,这可能会破坏您的页面,因为它可能会在任何一天停止工作。
如果你想这样做仍然感觉如果它是同步但仍然没有阻塞那么你应该使用async / await,也可能是一些基于承诺的ajax,如新的获取 API
async function foo() {
var res = await fetch(url)
console.log(res.ok)
var json = await res.json()
console.log(json)
}
修改强> 当页面被导航或关闭时,chrome正在禁止在页面解雇时同步XHR 用户。这涉及beforeunload,unload,pagehide和visibilitychange。
如果这是您的使用案例,那么您可能需要查看 navigator.sendBeacon 而不是
页面也可以使用http标头或iframe的allow属性禁用sync req
使用 async:false
,您将获得一个被阻止的浏览器。
对于非阻塞同步解决方案,您可以使用以下命令:
ES6 / ECMAScript2015
使用ES6,你可以使用发电机& 合作图书馆:
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
使用ES7,你可以使用asyc等待:
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
})();
}
我使用了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');
}
}
我添加了'JSON'的 dataType ,并将 .responseText 更改为 responseJSON 。
我还使用返回对象的 statusText 属性检索状态。请注意,这是Ajax响应的状态,而不是JSON是否有效。
后端必须以正确(格式正确)的JSON返回响应,否则返回的对象将是未定义的。
回答原始问题时需要考虑两个方面。一个是告诉Ajax同步执行(通过设置 async:false ),另一个是通过调用函数的return语句返回响应,而不是回调函数。
我也尝试过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;
}
请注意,上述代码仅适用于异步 false 的情况。如果您要设置 async:true ,则返回的对象 jqxhr 在AJAX调用返回时无效,仅在异步调用结束后才会生效,但这是设置响应变量为时已晚。
这是一个例子:
$.ajax({
url: "test.html",
async: false
}).done(function(data) {
// Todo something..
}).fail(function(xhr) {
// Todo something..
});
首先,我们应该了解何时使用$ .ajax以及何时使用$ .get / $。发布
当我们需要对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
});
这是我使用jQuery对ASYNC请求的简单实现。我希望这对任何人都有帮助。
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();
由于不推荐使用 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's 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;
};
这是我的“ 主题”名称空间:
var Thread = {
sleep: function(ms) {
var start = Date.now();
while (true) {
var clock = (Date.now() - start);
if (clock >= ms) break;
}
}
};
这就是我所说的:
var d1 = new Date();
console.log('start ' + d1.toLocaleTimeString());
Thread.sleep(10000);
var d2 = new Date();
console.log('end ' + d2.toLocaleTimeString());
如果查看控制台,我们会得到以下结果:
start 1:41:21 PM
end 1:41:31 PM