Javascript 是否有任何理由使用同步 XMLHttpRequest?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2088318/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there any reason to use a synchronous XMLHttpRequest?
提问by Darrell Brogdon
It seems most everyone does asynchronous requests with XMLHttpRequest but obviously the fact that there is the ability to do synchronous requests indicates there might be a valid reason to do so. So what might that valid reason be?
似乎大多数人都使用 XMLHttpRequest 进行异步请求,但显然有能力进行同步请求这一事实表明这样做可能是有正当理由的。那么这个正当理由可能是什么呢?
采纳答案by D.C.
I think they might become more popular as HTML 5 standards progress. If a web application is given access to web workers, I could foresee developers using a dedicated web worker to make synchronous requests for, as Jonathan said, to ensure one request happens before another. With the current situation of one thread, it is a less than ideal design as it blocks until the request is complete.
我认为随着 HTML 5 标准的发展,它们可能会变得更受欢迎。如果 Web 应用程序可以访问 Web Worker,我可以预见开发人员会使用专用的 Web Worker 来发出同步请求,正如 Jonathan 所说,以确保一个请求在另一个请求之前发生。对于一个线程的当前情况,它是一种不太理想的设计,因为它会阻塞直到请求完成。
回答by Sami Samhuri
Synchronous XHRs are useful for saving user data. If you handle the beforeunloadevent you can upload data to the server as the user closes the page.
同步 XHR 可用于保存用户数据。如果您处理该beforeunload事件,您可以在用户关闭页面时将数据上传到服务器。
If this were done using the async option, then the page could close before the request completes. Doing this synchronously ensures the request completes or fails in an expected way.
如果这是使用 async 选项完成的,则页面可能会在请求完成之前关闭。同步执行此操作可确保请求以预期方式完成或失败。
回答by vol7ron
Update:
更新:
The below hinted at - but was unsuccessful in delivering - that with the advent of better asynchronous request handling, there really is no reason to use synchronous requests, unless intending to purposely block the users from doing anything until a request is complete - sounds malicious :)
下面暗示 - 但未能成功交付 - 随着更好的异步请求处理的出现,真的没有理由使用同步请求,除非有意阻止用户在请求完成之前做任何事情 - 听起来很恶意: )
Although, this may sound bad, there may be times where it's important that a request (or series of requests) occur before a user leaves a page, or before an action is performed - blocking other code execution (e.g., preventing back button) could possibly reduce errors/maintenance for a poorlydesigned system; that said, I've never seen it in the wildand stress that it should be avoided.
虽然这听起来很糟糕,但有时在用户离开页面之前或执行操作之前发生一个请求(或一系列请求)很重要 - 阻止其他代码执行(例如,阻止后退按钮)可能可能会减少设计不良的系统的错误/维护;也就是说,我从未在野外见过它,并强调应该避免它。
Libraries, like promise, feign synchronicity by chaining processes via callbacks. This suits the majority of development needs where the desire is to have ordered, non-blocking events that enable the browsers to retain responsiveness for the user (good UX).
库,如promise,通过回调链接进程来伪装同步。这适合大多数开发需求,其中希望拥有有序的、非阻塞的事件,使浏览器能够为用户保留响应能力(良好的 UX)。
As stated in the Mozilla docsthere are cases where you have to use synchronous requests; however, also listed is a workaround that uses beacon(not available in IE/Safari) for such cases. While this is experimental, if it ever reaches standards-acceptance, it could possibly put a nail in the synchronous-request coffin.
正如Mozilla 文档中所述,在某些情况下您必须使用同步请求;但是,还列出了针对此类情况使用信标(在 IE/Safari 中不可用)的解决方法。虽然这是实验性的,但如果它达到标准验收,它可能会在同步请求棺材中钉上钉子。
You'd want to perform synchronous calls in any sort of transaction-like processing, or wherever any order of operation is necessary.
您可能希望在任何类型的类似事务的处理中或任何需要任何操作顺序的地方执行同步调用。
For instance, let's say you want to customize an event to log you out after playing a song. If the logout operation occurs first, then the song will never be played. This requires synchronizing the requests.
例如,假设您想自定义一个事件以在播放歌曲后将您注销。如果注销操作先发生,则歌曲将永远不会播放。这需要同步请求。
Another reason would be when working with a WebService, especially when performing math on the server.
另一个原因是在使用 WebService 时,尤其是在服务器上执行数学运算时。
Example:Server has a variable with value of 1.
Step (1) Perform Update: add 1 to variable Step (2) Perform Update: set variable to the power of 3 End Value: variable equals 8If Step (2) occurs first, then the end value is 2, not 8; thus order of operation matters and synchronization is needed.
示例:服务器有一个值为 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;因此操作顺序很重要并且需要同步。
There are very few times that a synchronous call may be justified in a common real world example. Perhaps when clicking login and then clicking a portion of the site that requires a user to be logged in.
在常见的现实世界示例中,很少有时间可以证明同步调用是合理的。可能是在单击登录然后单击需要用户登录的站点部分时。
As others have said, it will tie up your browser, so stay away from it where you can.
正如其他人所说,它会占用您的浏览器,因此请尽可能远离它。
Instead of synchronous calls, though, often users want to stop an event that is currently loading and then perform some other operation. In a way this is synchronization, since the first event is quit before the second begins. To do this, use the abort() method on the xml connection object.
但是,用户通常希望停止当前正在加载的事件,然后执行一些其他操作,而不是同步调用。从某种意义上说,这就是同步,因为第一个事件在第二个开始之前退出。为此,请对 xml 连接对象使用 abort() 方法。
回答by hobodave
I'd say that if you consider blocking the user's browser while the request completes acceptable, then sure use a synchronous request.
我想说的是,如果您考虑在请求完成可接受时阻止用户的浏览器,那么一定要使用同步请求。
If serialization of requests is your aim, then this can be accomplished using async requests, by having the onComplete callback of your previous request fire the next in line.
如果您的目标是请求序列化,那么这可以使用异步请求来完成,方法是让前一个请求的 onComplete 回调触发下一个。
回答by hyponiq
I can see a use for synchronous XHR requests to be used when a resource in a variable location must be loaded before other static resources in the page that depend on the first resource to fully function. In point of fact, I'm implementing such an XHR request in a little sub-project of my own whereas JavaScript resources reside in variable locations on the server depending on a set of specific parameters. Subsequent JavaScript resources rely on those variable resources and such files MUST be guaranteed to load before the other reliant files are loaded, thus making the application whole.
我可以看到同步 XHR 请求的使用,当可变位置中的资源必须在页面中依赖第一个资源才能完全运行的其他静态资源之前加载时。事实上,我正在我自己的一个小子项目中实现这样一个 XHR 请求,而 JavaScript 资源则位于服务器上的可变位置,具体取决于一组特定参数。后续的 JavaScript 资源依赖于这些可变资源,并且必须保证在加载其他依赖文件之前加载这些文件,从而使应用程序完整。
That idea foundation really kind of expands on vol7ron's answer. Transaction-based procedures are really the only time where synchronous requests should be made. In most other cases, asynchronous calls are the better alternative in which, after the call, the DOM is updated as necessary. In many cases, such as user-based systems, you could have certain features locked to "unauthorized users" until they have, per se, logged in. The those features, after the asynchronous call, are unlocked via a DOM update procedure.
这个想法基础确实扩展了 vol7ron 的答案。基于事务的过程实际上是唯一应该发出同步请求的时间。在大多数其他情况下,异步调用是更好的选择,在调用之后,DOM 会根据需要进行更新。在许多情况下,例如基于用户的系统,您可以将某些功能锁定给“未经授权的用户”,直到他们本身登录为止。异步调用之后,这些功能将通过 DOM 更新过程解锁。
I'd have to finally say that I agree with most individuals' points on the matter: wherever possible, synchronous XHR requests should be avoided as, with the way it works, the browser locks up with synchronous calls. When implementing synchronous requests, they should be done in a manner where the browser would normally be locked, anyway, say in the HEAD section before page loading actually occurs.
最后我不得不说我同意大多数人的观点:只要有可能,就应该避免同步 XHR 请求,因为在它的工作方式中,浏览器会锁定同步调用。在实现同步请求时,它们应该以浏览器通常被锁定的方式完成,无论如何,在页面加载实际发生之前在 HEAD 部分说。
回答by Alexandre Avrane
There are many real world cases where blocking the UI is exactly the desired behaviour.
有许多现实世界的案例,其中阻止 UI 正是所需的行为。
Take an app with multiple fields and some fields must be validated by a xmlhttp call to a remote server providing as input this field's value and other fields values.
以具有多个字段的应用程序为例,某些字段必须通过对远程服务器的 xmlhttp 调用进行验证,该远程服务器提供此字段的值和其他字段值作为输入。
In synchronous mode, the logic is simple, the blocking experienced by the user is very short and there is no problem.
在同步模式下,逻辑简单,用户体验的阻塞很短,没有问题。
In async mode, the user may change the values of any other fields while the initial one is being validated. These changes will trigger other xmlhttp calls with values from the initial field not yet validated. What happens if the initial validation failed ? Pure mess. If sync mode becomes deprecated and prohibited, the application logic becomes a nightmare to handle. Basically the application has to be re-written to manage locks (eg. disable other items during validation processes). Code complexity increases tremendously. Failing to do so may lead to logic failure and ultimately data corruption.
在异步模式下,用户可以在验证初始字段时更改任何其他字段的值。这些更改将使用尚未验证的初始字段中的值触发其他 xmlhttp 调用。如果初始验证失败会怎样?纯粹的混乱。如果同步模式被弃用和禁止,应用程序逻辑将成为处理的噩梦。基本上必须重新编写应用程序以管理锁(例如,在验证过程中禁用其他项目)。代码复杂度大大增加。否则可能会导致逻辑故障并最终导致数据损坏。
Basically the question is: what is more important, non-blocked UI experience or risk of data corruption ? The answer should remain with the application developer, not the W3C.
基本上问题是:什么更重要,非阻塞的 UI 体验或数据损坏的风险?答案应该由应用程序开发人员决定,而不是 W3C。
回答by jahu
As of 2015 desktop javascript apps are becoming more popular. Usually in those apps when loading local files (and loading them using XHR is a perfectly valid option), the load speed is so fast that there is little point overcomplicating the code with async. Of course there might be cases where async is the way to go (requesting content from the internet, loading really big files or a huge number of files in a single batch), but otherwise sync works just fine (and is much easier to use).
截至 2015 年,桌面 javascript 应用程序变得越来越流行。通常在这些应用程序中加载本地文件时(并且使用 XHR 加载它们是一个非常有效的选项),加载速度非常快,以至于用 async 使代码过于复杂几乎没有意义。当然,在某些情况下,异步是可行的(从 Internet 请求内容,加载非常大的文件或在单个批处理中加载大量文件),但其他情况下同步工作正常(并且更易于使用) .
回答by Henry Chan
jQuery uses synchronous AJAX internally under some circumstances. When inserting HTML that contains scripts, the browser will not execute them. The scripts need to be executed manually. These scripts may attach click handlers. Assume a user clicks on an element before the handler is attached and the page would not function as intended. Therefore to prevent race conditions, synchronous AJAX would be used to fetch those scripts. Because synchronous AJAX effectively blocks everything else, it can be sure that scripts and events execute in the right order.
在某些情况下,jQuery 在内部使用同步 AJAX。插入包含脚本的 HTML 时,浏览器不会执行它们。脚本需要手动执行。这些脚本可能会附加点击处理程序。假设用户在附加处理程序之前点击了一个元素,页面将无法按预期运行。因此,为了防止竞争条件,将使用同步 AJAX 来获取这些脚本。因为同步 AJAX 有效地阻止了其他一切,所以可以确保脚本和事件以正确的顺序执行。
回答by Jesse Gordon
Reason:
原因:
Let's say you have an ajax application which needs to do half a dozen http gets to load various data from the server before the user can do any interaction.
假设您有一个 ajax 应用程序,它需要在用户进行任何交互之前执行六次 http 访问以从服务器加载各种数据。
Obviously you want this triggered from onload.
显然,您希望从 onload 触发。
Synchronous calls work very well for this without any added complexity to the code. It is simple and straightforward.
同步调用对此非常有效,而不会增加代码的复杂性。它简单明了。
Drawback:
退税:
The only drawback is that your browser locks up until all data is loaded or a timeout happens. As for the ajax application in question, this isn't much of a problem because the application is of no use until all the initial data is loaded anyway.
唯一的缺点是您的浏览器会在加载所有数据或发生超时之前锁定。至于有问题的 ajax 应用程序,这不是什么大问题,因为在加载所有初始数据之前,该应用程序是没有用的。
Alternative?
选择?
However many browsers lock up all windows/tabs when while the javascript is busy in any one of them, which is a stupid browser design problem - but as a result blocking on possibly slow network gets is not polite if it keeps users from using other tabs while waiting for ajax page to load.
然而,当 javascript 在其中任何一个忙时,许多浏览器会锁定所有窗口/选项卡,这是一个愚蠢的浏览器设计问题 - 但结果是,如果阻止用户使用其他选项卡,则阻止可能缓慢的网络获取是不礼貌的在等待 ajax 页面加载时。
However, it looks like synchronous gets have been removed or restricted from recent browsers anyway. I'm not sure if that's because somebody decided they were just always bad, or if browser writers were confused by the WC Working Draft on the topic.
但是,无论如何,同步获取似乎已从最近的浏览器中删除或限制。我不确定这是不是因为有人认为他们总是很糟糕,或者浏览器作者是否对 WC 工作草案对该主题感到困惑。
http://www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/#the-open-methoddoes make it look like (see section 4.7.3) you are not allowed to set a timeout when using blocking mode. Seems counter intuitive to me: Whenever one does blocking IO it's polite to set a reasonable timeout, so why allow blocking io but not with a user specified timeout?
http://www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/#the-open-method确实使它看起来像(参见第 4.7.3 节)使用阻塞模式时不允许设置超时. 对我来说似乎违反直觉:每当阻止 IO 时,设置合理的超时是礼貌的,那么为什么允许阻止 io 但不允许用户指定的超时呢?
My opinion is that blocking IO has a vital role in some situations but must be implemented correctly. While it is not acceptable for one browser tab or window to lock up all other tabs or windows, that's a browser design flaw. Shame where shame is due. But it is perfectly acceptable in some cases for an individual tab or window to be non-responsive for a couple of seconds (i.e. using blocking IO/HTTP GET) in some situations -- for example, on page load, perhaps a lot of data needs to be before anything can be done anyway. Sometimes properly implemented blocking code is the cleanest way to do it.
我的观点是,阻塞 IO 在某些情况下具有至关重要的作用,但必须正确实施。虽然一个浏览器选项卡或窗口锁定所有其他选项卡或窗口是不可接受的,但这是浏览器设计缺陷。羞耻的地方应该感到羞耻。但在某些情况下,单个选项卡或窗口在某些情况下(即使用阻塞 IO/HTTP GET)无响应几秒钟是完全可以接受的——例如,在页面加载时,可能有很多数据在任何事情都可以做之前需要先。有时正确实现的阻塞代码是最干净的方法。
Of course equivalent function in this case can be obtained using asynchronous http gets, but what sort of goofy routine is required?
当然这种情况下的等价函数可以使用异步httpgets来获得,但是需要什么样的傻瓜例程呢?
I guess I would try something along these lines:
我想我会尝试以下方法:
On document load, do the following: 1: Set up 6 global "Done" flag variables, initialized to 0. 2: Execute all 6 background gets (Assuming the order didn't matter)
在文档加载时,执行以下操作:1:设置 6 个全局“完成”标志变量,初始化为 0。2:执行所有 6 个后台获取(假设顺序无关紧要)
Then, the completion callbacks for each of the 6 http get's would set their respective "Done" flags. Also, each callback would check all the other done flags to see if all 6 HTTP gets had completed. The last callback to complete, upon seeing that all others had completed, would then call the REAL init function which would then set everything up, now that the data was all fetched.
然后,6 个 http get 的完成回调将设置它们各自的“完成”标志。此外,每个回调都会检查所有其他完成标志,以查看是否所有 6 个 HTTP 获取都已完成。最后一个要完成的回调,在看到所有其他回调都已完成后,将调用 REAL init 函数,该函数将设置所有内容,现在数据已全部获取。
If the order of the fetching mattered -- or if the webserver was unable to accept multiple requests at same time -- then you would need something like this:
如果获取的顺序很重要——或者如果网络服务器无法同时接受多个请求——那么你需要这样的东西:
In onload(), the first http get would be launched. In it's callback, the second one would be launched. In it's callback, the third -- and so on and so forth, with each callback launching the next HTTP GET. When the last one returned, then it would call the real init() routine.
在 onload() 中,将启动第一个 http get。在它的回调中,将启动第二个。在它的回调中,第三个——依此类推,每个回调启动下一个 HTTP GET。当最后一个返回时,它将调用真正的 init() 例程。
回答by Stijn de Witt
SYNC vs ASYNC: What is the difference?
SYNC 与 ASYNC:有什么区别?
Basically it boils down to this:
基本上它归结为:
console.info('Hello, World!');
doSomething(function handleResult(result) {
console.info('Got result!');
});
console.info('Goodbye cruel world!');
When doSomethingis synchronousthis would print:
如果doSomething是同步的,这将打印:
Hello, World!
Got result!
Goodbye cruel world!
In contrast, if doSomethingis asynchronous, this would print:
相反,如果doSomething是asynchronous,这将打印:
Hello, World!
Goodbye cruel world!
Got result!
Because the function doSomethingis doing it's work asynchronously, it returns before it's work is done. So we only get the result after printing Goodbye cruel world!
因为函数doSomething是异步执行它的工作,所以它在工作完成之前返回。所以我们只有打印后才能得到结果Goodbye cruel world!
If we are depending on the result of an asynch call, we need to place the depending code in the callback:
如果我们依赖于异步调用的结果,我们需要将依赖代码放在回调中:
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!');
}
});
As such, just the fact that 2 or three things need to happen in order is no reason to do them synchronously (though sync code is easier for most people to work with).
因此,仅仅需要按顺序发生 2 或 3 件事这一事实并不是同步执行它们的理由(尽管同步代码对大多数人来说更容易使用)。
WHY USE SYNCHRONOUS XMLHTTPREQUEST?
为什么要使用同步 XMLHTTPREQUEST?
There are some situations where you need the result before the called function completes. Consider this scenario:
在某些情况下,您需要在被调用函数完成之前获得结果。考虑这个场景:
function lives(name) {
return (name !== 'Elvis');
}
console.info('Elvis ' + (lives('Elvis') ? 'lives!' : 'has left the building...');
Suppose we have no control over the calling code (the console.infoline) and need to change function livesto ask the server... There is no way we can do an async request to the server from within livesand still have our response before livescompletes. So we wouldn't know whether to return trueor false. The only way to get the result before the function completes is by doing a synchronous request.
假设我们无法控制调用代码(console.info行)并且需要更改函数lives以询问服务器......我们无法从内部向服务器发出异步请求lives并且在lives完成之前仍然有我们的响应。所以我们不知道是返回true还是false. 在函数完成之前获得结果的唯一方法是执行同步请求。
As Sami Samhurimentions in his answer, a very real scenario where you may need an answer to your server request before your function terminates is the onbeforeunloadevent, as it's the last function from your app that will ever run before the window being closed.
正如Sami Samhuri他在回答中提到的那样,一个非常真实的场景是在您的函数终止之前您可能需要对服务器请求的回答是onbeforeunload事件,因为它是您的应用程序中将在窗口关闭之前运行的最后一个函数。
I DON'T NEED SYNCH CALLS, BUT I USE THEM ANYWAY AS THEY ARE EASIER
我不需要同步呼叫,但我还是会使用它们,因为它们更容易
Please don't. Synchronous calls lock up your browser and make the app feel unresponsive. But you are right. Async code is harder. There is, however a way to make dealing with it much easier. Not as easy as sync code, but it's getting close: Promises.
请不要。同步调用会锁定您的浏览器并使应用程序感觉无响应。但你是对的。异步代码更难。然而,有一种方法可以更轻松地处理它。不像同步代码那么容易,但它越来越接近:Promises。
Here is an example: Two asynch calls should both complete succesfully before a third segment of code may run:
下面是一个例子:在第三段代码可以运行之前,两个异步调用都应该成功完成:
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();
});
Here is how you would implement bookHotel:
以下是您将如何实施bookHotel:
function bookHotel() {
return new Promise(function(resolve, reject){
if (roomsAvailable()) {
var reservation = reserveRoom();
resolve(reservation);
}
else {
reject(new Error('Could not book a reservation. No rooms available.'));
}
});
}
See also: Write Better JavaScript with Promises.

