似乎大多数人都使用XMLHttpRequest执行异步请求,但显然有能力执行同步请求这一事实表明可能有正当理由这样做。那么这个有效的理由是什么呢?
答案 0 :(得分:29)
同步XHR对于保存用户数据非常有用。如果您处理beforeunload
事件,则可以在用户关闭页面时将数据上传到服务器。
如果使用async选项完成此操作,则页面可能会在请求完成之前关闭。同步执行此操作可确保请求以预期方式完成或失败。
答案 1 :(得分:26)
我认为随着HTML 5标准的进步,它们可能会变得更受欢迎。如果Web应用程序可以访问Web工作者,我可以预见开发人员使用专门的Web工作者来制作同步请求,正如Jonathan所说,确保一个请求发生在另一个请求之前。对于一个线程的当前情况,它是一个不太理想的设计,因为它阻塞直到请求完成。
答案 2 :(得分:13)
以下暗示 - 但未能成功交付 - 随着更好的异步请求处理的出现,确实没有理由使用同步请求,除非打算故意阻止用户做任何事情直到请求完成 - 听起来很恶意:)
虽然这可能听起来很糟糕,但有时在用户离开页面之前或执行操作之前发生请求(或一系列请求)非常重要 - 阻止其他代码执行(例如,阻止其他代码执行)按钮)可能会减少设计不良的系统的错误/维护;那说,我从来没有在 wild 中看过它,并强调应该避免它。
像promise这样的库通过回调链接进程来假装同步性。这适合大多数开发需求,其中需要有序的,非阻塞事件,使浏览器能够保持对用户的响应(良好的用户体验)。
作为stated in the Mozilla docs,您可能需要使用同步请求;但是,还列出了一种使用 beacon (在IE / Safari中不可用)的解决方法。虽然这是实验性的,如果它达到标准接受,它可能会在同步请求棺材中钉一个钉子。
您希望在任何类似交易的处理中执行同步调用,或者需要任何操作顺序的地方。
例如,假设您要自定义一个事件,以便在播放歌曲后将您注销。如果首先发生注销操作,则永远不会播放该歌曲。这需要同步请求。
另一个原因是使用WebService时,尤其是在服务器上执行数学运算时。
示例:服务器有一个值为1的变量。
Step (1) Perform Update: add 1 to variable Step (2) Perform Update: set variable to the power of 3 End Value: variable equals 8
如果首先发生步骤(2),则结束值为2,而不是8;因此,操作顺序很重要,需要同步。
在一个普通的现实世界示例中,很少有同步调用可以被证明是合理的。也许在单击登录然后单击需要用户登录的站点部分时。
正如其他人所说,它会占用您的浏览器,因此请尽量远离它。
但是,用户通常希望停止当前正在加载的事件,然后执行其他操作,而不是同步调用。在某种程度上,这是同步,因为第一个事件在第二个事件开始之前退出。为此,请在xml连接对象上使用abort()方法。
答案 3 :(得分:8)
我会说如果您考虑在请求完成时阻止用户的浏览器,那么请确保使用同步请求。
如果请求序列化是您的目标,那么可以使用异步请求来完成此操作,方法是让您的上一个请求的onComplete回调触发下一行。
答案 4 :(得分:6)
答案 5 :(得分:5)
有许多现实世界的案例,阻止UI正是所期望的行为。
获取具有多个字段的应用程序,并且必须通过对远程服务器的xmlhttp调用来验证某些字段,并将此字段的值和其他字段值作为输入提供。
在同步模式下,逻辑很简单,用户遇到的阻塞很短,没有问题。
在异步模式下,用户可以在验证初始字段时更改任何其他字段的值。这些更改将触发其他xmlhttp调用,其中包含尚未验证的初始字段中的值。如果初始验证失败会怎样?纯洁的混乱。如果同意模式被弃用和禁止,应用程序逻辑将成为一个需要处理的噩梦。基本上,必须重新编写应用程序来管理锁(例如,在验证过程中禁用其他项)。代码复杂性大大增加。如果不这样做可能会导致逻辑失败并最终导致数据损坏。
基本上问题是:什么更重要,非阻止的UI体验或数据损坏的风险?答案应该由应用程序开发人员保留,而不是W3C。
答案 6 :(得分:4)
jQuery在某些情况下会在内部使用同步AJAX。插入包含脚本的HTML时,浏览器不会执行它们。脚本需要手动执行。这些脚本可能附加点击处理程序。假设用户在附加处理程序之前单击元素,并且页面将无法按预期运行。因此,为防止竞争条件,将使用同步AJAX来获取这些脚本。因为同步AJAX有效地阻止了其他所有内容,所以可以确保脚本和事件以正确的顺序执行。
答案 7 :(得分:3)
截至2015年,桌面javascript应用程序正变得越来越流行。通常在这些应用程序中加载本地文件(并使用XHR加载它们是一个非常有效的选项)时,加载速度非常快,以至于使用异步使代码过于复杂。当然可能存在异步是要走的路(从互联网上请求内容,在一个批次中加载真正的大文件或大量文件),但是否则同步工作得很好(并且更容易使用)
答案 8 :(得分:2)
如果您在生产代码中进行同步调用会怎样?
天空陨落。
不用说,用户不喜欢被锁定的浏览器。
答案 9 :(得分:2)
SYNC vs ASYNC:有什么区别?
基本上归结为:
siege -c10 -t60s http://127.0.0.1
当console.info('Hello, World!');
doSomething(function handleResult(result) {
console.info('Got result!');
});
console.info('Goodbye cruel world!');
同步时,会打印:
doSomething
相反,如果Hello, World!
Got result!
Goodbye cruel world!
异步,则打印出来:
doSomething
因为函数Hello, World!
Goodbye cruel world!
Got result!
正在异步地工作,所以它会在它完成工作之前返回。所以我们只在打印doSomething
如果我们依赖于异步调用的结果,我们需要将依赖代码放在回调中:
Goodbye cruel world!
因此,只需要按顺序发生两到三件事就没有理由同步进行(虽然同步代码对大多数人来说更容易使用)。
为什么使用同步XMLHTTPREQUEST?
在某些情况下,您需要在被调用函数完成之前获得结果。请考虑以下情况:
console.info('Hello, World!');
doSomething(function handleResult(result) {
console.info('Got result!');
if (result === 'good') {
console.info('I feel great!');
}
else {
console.info('Goodbye cruel world!');
}
});
假设我们无法控制调用代码(function lives(name) {
return (name !== 'Elvis');
}
console.info('Elvis ' + (lives('Elvis') ? 'lives!' : 'has left the building...');
行)并需要更改函数console.info
来询问服务器...我们无法对该服务器执行异步请求服务器来自lives
,并且在lives
完成之前仍然有我们的响应。因此,我们无法知道是返回lives
还是true
。在函数完成之前获取结果的唯一方法是执行同步请求。
正如false
在他的回答中提到的那样,一个非常真实的场景,你可能需要在你的函数终止之前回答你的服务器请求是Sami Samhuri
事件,因为它是最后一个函数来自您的应用程序将在关闭窗口之前运行。
我不需要同步电话,但我会使用它们,因为它们更容易
请不要。同步调用会锁定您的浏览器并使应用程序感觉无响应。但你是对的。异步代码更难。然而,有一种方法可以更容易地处理它。不像同步代码那么容易,但它已接近:Promise s。
以下是一个示例:在第三段代码运行之前,两个异步调用都应该成功完成:
onbeforeunload
以下是如何实施var carRented = rentCar().then(function(car){
gasStation.refuel(car);
});
var hotelBooked = bookHotel().then(function(reservation) {
reservation.confirm();
});
Promise.all([carRented, hotelBooked]).then(function(){
// At this point our car is rented and our hotel booked.
goOnHoliday();
});
:
bookHotel
答案 10 :(得分:2)
原因:
假设你有一个ajax应用程序需要做半打http才能在用户进行任何交互之前从服务器加载各种数据。
显然你想从onload触发这个。
同步调用对此非常有效,而不会增加代码的复杂性。它简单明了。
缺点:
唯一的缺点是浏览器会锁定,直到加载所有数据或发生超时。至于有问题的ajax应用程序,这不是什么大问题,因为在完成所有初始数据的加载之前,应用程序是没有用的。
替代?
然而,当javascript忙于其中任何一个时,许多浏览器会锁定所有窗口/标签,这是一个愚蠢的浏览器设计问题 - 但是因此阻止可能很慢的网络获取是不礼貌的,如果它保持用户在等待加载ajax页面时使用其他选项卡。
但是,无论如何,看起来已经从最近的浏览器中删除或限制了同步获取。我不确定是不是因为有人认为他们总是不好,或者浏览器编写者对WC工作草案感到困惑。
http://www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/#the-open-method确实看起来像(参见第4.7.3节),在使用阻止模式时不允许设置超时。对我来说似乎直截了当:每当有人阻止IO时,设置合理的超时是礼貌的,那么为什么允许阻止io而不是用户指定的超时呢?
我认为阻止IO在某些情况下起着至关重要的作用,但必须正确实施。虽然一个浏览器选项卡或窗口无法锁定所有其他选项卡或窗口,但这是一个浏览器设计缺陷。羞耻到底。但在某些情况下,单个选项卡或窗口在某些情况下无响应(即使用阻塞IO / HTTP GET)是完全可以接受的 - 例如,在页面加载时,可能是大量数据无论如何都需要做任何事情。有时正确实现阻塞代码是最干净的方法。
当然,使用异步http gets可以获得这种情况下的等效函数,但是需要什么样的高效例程呢?
我想我会尝试这些方法:
在文档加载时,执行以下操作: 1:设置6个全局“完成”标志变量,初始化为0。 2:执行所有6个背景获取(假设顺序无关紧要)
然后,6个http get的每一个的完成回调将设置它们各自的“完成”标志。 此外,每个回调都会检查所有其他已完成的标志,以查看是否所有6个HTTP都已完成。在看到所有其他人完成后,最后一个回调完成,然后调用REAL init函数,然后设置所有内容,现在数据全部被提取。
如果提取的顺序很重要 - 或者如果网络服务器无法同时接受多个请求 - 那么您需要这样的内容:
在onload()中,将启动第一个http get。 在它的回调中,第二个将被启动。 在它的回调中,第三个 - 依此类推,每个回调启动下一个HTTP GET。当最后一个返回时,它将调用真正的init()例程。
答案 11 :(得分:2)
XMLHttpRequest
传统上用于异步请求。有时(对于调试或特定业务逻辑),您希望在一个页面中更改所有/几个异步调用以进行同步。
您希望在不更改JS代码中的所有内容的情况下执行此操作。 async / sync标志为您提供了这种能力,如果设计正确,您只需更改代码中的一行/在执行期间更改一个var
的值。
答案 12 :(得分:2)
我在开发代码时使用同步调用 - 无论你在服务器上下往服务器时做了什么都可以掩盖错误的原因。
当它工作时,我让它异步,但我尝试包含一个中止计时器和故障回调,因为你永远不知道...
答案 13 :(得分:2)
有时你的行动取决于其他人。例如,只有在A完成时才能启动动作B.同步方法通常用于避免race conditions。有时使用同步调用是一种更简单的实现,然后创建复杂的逻辑来检查彼此依赖的异步调用的每个状态。
这种方法的问题在于,您“阻止”用户的浏览器,直到操作完成(直到请求返回,完成,加载等)。所以使用时要小心。
答案 14 :(得分:2)
在检查用户名不存在的情况下,我用它来验证用户名。
我知道异步执行此操作会更好,但我应该为此特定验证规则使用不同的代码。我解释得更好。我的验证设置使用一些验证函数,它们返回true或false,具体取决于数据是否有效。
由于函数必须返回,我不能使用异步技术,所以我只是让它同步并希望服务器能够及时回答不要太明显。如果我使用了AJAX回调,那么我将不得不以其他验证方法的方式处理其余的执行。
答案 15 :(得分:1)
Firefox(可能是所有非IE浏览器)不支持异步XHR timeOut。
HTML5 WebWorkers支持超时。因此,您可能希望使用超时将同步XHR请求包装到WebWorker,以实现具有超时行为的类似异步的XHR。
答案 16 :(得分:1)
我只是遇到这样一种情况,即使用forEach(和for循环)连续调用的url列表的异步请求将导致其余请求被取消。我切换到同步,他们按预期工作。
答案 17 :(得分:1)
在移动广告业务中,使用同步HTTP请求是一种常见的做法。
构建应用程序的公司(又称“发布商”)通常会投放广告来产生收入。为此,他们将广告SDK安装到其应用中。存在很多(MoPub,Ogury,TapJob,AppNext,Google Ads AdMob)。
这些SDK将在网络视图中投放广告。
向用户投放广告时,必须具有顺畅的体验,尤其是在播放视频时。任何时候都不应有缓冲或加载。
要解决此问题,请使用precaching
。媒体(图片/视频/等)在Webview的背景中同步加载的位置。
为什么不异步呢?
onload
事件,以了解广告何时“准备就绪”投放给用户随着synchronous XMLHttpRequests的淘汰,除非可以确定其他方法,否则将来极有可能迫使广告业务更改标准。
答案 18 :(得分:0)
这是一个很好的理由。我想做一个http请求,然后根据结果调用input type = file上的click()。异步xhr或fetch不可能实现这一点。回调丢失了上下文“用户操作”,因此忽略了调用click()。同步xhr救了我的培根。
onclick(event){
//here I can, but I don't want to.
//document.getElementById("myFileInput").click();
fetch("Validate.aspx", { method : "POST", body: formData, credentials: "include" })
.then((response)=>response.json())
.then(function (validResult) {
if (validResult.success) {
//here, I can't.
document.getElementById("myFileInput").click();
}
});
}
答案 19 :(得分:0)
同步XHR对于(非生产性的)内部工具和/或框架开发非常有用。想象一下,例如,您想在首次访问时同步加载代码库,如下所示:
get draw()
{
if (!_draw)
{
let file;
switch(config.option)
{
case 'svg':
file = 'svgdraw.js';
break;
case 'canvas':
file = 'canvasdraw.js';
break;
default:
file = 'webgldraw.js';
}
var request = new XMLHttpRequest();
request.open('GET', file, false);
request.send(null);
_draw = eval(request.responseText);
}
return _draw;
}
在陷入头昏眼花,盲目反省邪恶的评估之前,请记住,这仅用于本地测试。对于生产版本,已设置_draw。
因此,您的代码可能如下所示:
foo.drawLib.draw.something(); //loaded on demand
这只是没有XHR同步就无法完成的一个例子。您可以预先加载此库(是的),或做一个Promise / Callback,但是如果没有同步XHR,就无法同步加载该库。考虑一下这种事情可以清理您的代码多少……
使用此工具和框架(在本地运行)可以执行的操作限制仅受您的想象力限制。但是,似乎在JavaScript世界中想象力是有限的。