我有一个提供标准扩展点的JavaScript小部件。其中之一是beforereate函数。它应该返回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,而不是在回调中返回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执行Ajax调用。Get(…);
然后再打开一次
jQuery.ajaxSetup({async:true});
我想它的工作原理与@Adam建议的一样,但它可能对那些想要重新配置jQuery.get()或jQuery.post()到更详细的jQuery.ajax()语法的人有帮助。
所有这些答案都忽略了一点,即使用async:false执行Ajax调用将导致浏览器挂起,直到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();
}
我使用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”的数据类型,并将. 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;
}
注意,上面的代码只在async为false的情况下有效。如果设置async: true,返回的对象jqxhr将在AJAX调用返回时无效,只有在异步调用结束后才有效,但此时设置响应变量已经太迟了。
async: false会导致浏览器被阻塞。
对于非阻塞同步解决方案,您可以使用以下方法:
ES6/ECMAScript2015
在ES6中,你可以使用生成器和co库:
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中,你可以使用async await:
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: false,因为这个警告消息:
从Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27)开始,由于对用户体验的负面影响,主线程上的同步请求已被弃用。
Chrome甚至会在控制台发出警告:
主线程上的同步XMLHttpRequest已弃用,因为它会对最终用户的体验产生不利影响。更多帮助,请访问https://xhr.spec.whatwg.org/。
如果您正在做这样的事情,这可能会破坏您的页面,因为它可能在任何一天停止工作。
如果你想让它看起来仍然是同步的,但仍然不会阻塞,那么你应该使用async/await,可能还应该使用一些基于承诺的ajax,比如新的Fetch API
async function foo() {
var res = await fetch(url)
console.log(res.ok)
var json = await res.json()
console.log(json)
}
编辑
当用户正在浏览或关闭页面时,chrome正在禁用同步XHR。这包括前卸载,卸载,页面隐藏和可见性改变。
如果这是您的用例,那么您可能需要看看navigator。sendBeacon相反
页面也可以使用http headers或iframe的allow属性禁用sync req
首先,我们应该了解什么时候使用$。当我们使用$。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
});
这是我的简单实现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();
因为xmlhttpreonse同步操作已弃用,所以我提出了以下包装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;
};