我有一个提供标准扩展点的 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 请求?
beforecreate
。
从 jQuery documentation:您将 asynchronous 选项指定为 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( ... );
执行您的 Ajax 调用
然后再打开一次
jQuery.ajaxSetup({async:true});
我猜它的效果与@Adam 所建议的相同,但它可能对想要将他们的 jQuery.get()
或 jQuery.post()
重新配置为更复杂的 jQuery.ajax()
语法的人有所帮助。
优秀的解决方案!我注意到当我尝试实现它时,如果我在成功子句中返回一个值,它会以未定义的形式返回。我必须将它存储在一个变量中并返回该变量。这是我想出的方法:
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: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();
}
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) - 您不能同步执行此操作,jQuery 将忽略 async
标志。
$.ajax({
url: "testserver.php",
dataType: 'jsonp', // jsonp
async: false //IGNORED!!
});
对于 JSONP 调用,您可以使用:
对您自己的域的 Ajax 调用 - 并在服务器端进行跨域调用 更改您的代码以异步工作 使用 Frame.js 之类的“函数序列器”库(此答案)阻止 UI 而不是阻止执行(此答案)(我最喜欢的方式)
注意:由于以下警告消息,您不应使用 async: false
:
从 Gecko 30.0 (Firefox 30.0 / Thunderbird 30.0 / SeaMonkey 2.27) 开始,由于对用户体验的负面影响,主线程上的同步请求已被弃用。
Chrome 甚至在控制台中对此发出警告:
主线程上的同步 XMLHttpRequest 已被弃用,因为它会对最终用户的体验产生不利影响。如需更多帮助,请查看 https://xhr.spec.whatwg.org/。
如果您正在做这样的事情,这可能会破坏您的页面,因为它可能会在任何一天停止工作。
如果您想以一种仍然感觉像是同步但仍不阻塞的方式来执行此操作,那么您应该使用 async/await 并且可能还有一些基于新 Fetch API 之类的承诺的 ajax
async function foo() {
var res = await fetch(url)
console.log(res.ok)
var json = await res.json()
console.log(json)
}
当页面被用户导航离开或关闭时,编辑 chrome 正在处理Disallowing sync XHR in page dismissal。这涉及到 beforeunload、unload、pagehide 和 visibilitychange。
如果这是您的用例,那么您可能想看看 navigator.sendBeacon
页面也可以使用 http 标头或 iframe 的允许属性禁用同步请求
我使用了 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 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
使用 ES7,你可以只使用 asyc 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
})();
}
这是示例:
$.ajax({
url: "test.html",
async: false
}).done(function(data) {
// Todo something..
}).fail(function(xhr) {
// Todo something..
});
首先我们应该了解什么时候使用 $.ajax 以及什么时候使用 $.get/$.post
当我们需要对 ajax 请求进行低级控制时,例如请求标头设置、缓存设置、同步设置等,那么我们应该使用 $.ajax。
$.get/$.post:当我们不需要对ajax请求进行低级控制时。只需简单的get/post数据到服务器。它是简写
$.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;
};
由于最初的问题是关于 jQuery.get
,因此在此值得一提的是(如 here 所述)人们可以在 $.get()
中使用 async: false
但最好避免 它因为异步 XMLHTTPRequest
已被弃用(并且浏览器可能会给出警告):
$.get({
url: url,// mandatory
data: data,
success: success,
dataType: dataType,
async:false // to make it synchronous
});
async: false
的用法是 deprecated。如果您使用它,您将在控制台中看到以下消息:“主线程上的同步 XMLHttpRequest 已被弃用,因为它对最终用户的体验产生不利影响。获取更多帮助 xhr.spec.whatwg.org”https://www.taniarascia.com/how-to-promisify-an-ajax-call/
您也可以使用返回的jqxhr
变量,或者您可以在 Invocation &调用其中的函数。