我有一个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});
然后使用执行Ajax调用 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: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) - 您无法同步执行此操作,async
jQuery将忽略该标志.
$.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,也许还有一些基于promises的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的页面解雇.这涉及beforeunload,unload,pagehide和visibilitychange.
如果这是你的使用情况,那么你可能想看看navigator.sendBeacon代替
页面也可以使用http标头或iframe的allow属性禁用sync req
我使用了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; }
请注意,上述代码仅适用于async为false的情况.如果要设置async:true,则返回的对象jqxhr在AJAX调用返回时无效,仅在异步调用结束后才有效,但设置响应变量为时已晚.
随着async: false
你自己被阻止的浏览器.对于非阻塞同步解决方案,您可以使用以下内容:
使用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,您可以使用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.. });