简体   繁体   English

无阻塞同步AJAX

[英]Non-blocking Synchronous AJAX

Is there a way to perform a synchronous AJAX query that doesn't freeze the browser? 有没有一种方法可以执行不冻结浏览器的同步AJAX查询? In my opinion synchronous requests are a lot easier to work with in most cases, but the fact that they block other parts of the code from executing is a real killer. 在我看来,在大多数情况下,同步请求要容易得多,但是它们阻止了代码其他部分的执行,这是一个真正的杀手。 Is there a way to get synchronous AJAX without the negative side effects? 有没有办法获得同步AJAX而没有负面影响? (And yes, I realize that the term "Synchronous AJAX" is an oxymoron.) (是的,我意识到术语“同步AJAX”是矛盾的。)

No. Synchronous is, by definition, blocking. 否。按照定义,同步是阻塞。 Nothing can proceed until the process completes. 在该过程完成之前,无法进行任何操作。 That includes the rest of the UI in the web browser. 这包括Web浏览器中的其余UI。

It's supposed to be asynchronous, so the best approach is to design the code to work asynchronously. 应该是异步的,所以最好的方法是将代码设计为异步工作。

I'll provide an example of the bad side of effects of allowing such behavior. 我将提供一个示例,说明允许此类行为的不良后果。

Lets say you have this program: 假设您有以下程序:

<script>
var file = "foo.json";

function nullIt() {
    file = null;
}

function loadFile() {
    if (file != null) {
        synchronousLoad(file);//imagine the load takes 5 seconds
        alert("i just loaded: " + file);
    }
}

window.onload = loadFile;
</script>
<button onclick="nullIt()">click me</button>

The bad thing here- 这里的坏事-

  • while the synchronousLoad() is blocking for 5 seconds, the user clicks the button, and the event handler quickly runs to completion. synchronousLoad()阻塞5秒钟时,用户单击按钮,事件处理程序将快速运行到完成状态。
  • Now the file variable is null. 现在, file变量为null。
  • synchronousLoad() finishes and returns, letting execution resume on the next line of code synchronousLoad()完成并返回,从而使执行在下一行代码中恢复
  • but file is now null, and the message output to the user is broken. 但是file现在为空,并且输出给用户的消息已损坏。

The real issue here you cannot reason about your code the same way anymore. 真正的问题是您无法再以相同的方式来思考代码了。 Just because some fact was true on line 5, doesnt mean its still true on the very next line. 仅仅因为第5行中的某些事实是正确的,并不意味着在下一行中它仍然是正确的。 This makes it very difficult to write an error free program. 这使得编写无错误程序非常困难。

Some programming languages support multithreading, and you have to deal with these issues, although you have tools to help deal with these problems. 某些编程语言支持多线程,尽管您有帮助解决这些问题的工具,但您必须处理这些问题。 But, it's still a lot of extra effort on the programmers part. 但是,程序员仍然需要付出很多额外的努力。

Comparatively speaking, using callbacks to do asynchronous operations is ez-mode. 相对而言,使用回调执行异步操作是ez模式。

I don't think it is possible. 我认为不可能。 Instead of trying to use synchronous queries, you can use the asynchronous approach and use the AJAX done event. 您可以使用异步方法并使用AJAX done事件,而不是尝试使用同步查询。

Example using jQuery.ajax() 使用jQuery.ajax()的示例

jQuery.ajax({
    url: "URL HERE",
    data: "whatever you are sending"
}).done(function (data) {
    // Do things with data
});

So, instead of using a synchronous request, you can use the Asynchronous request and just execute code AFTER the request has completed. 因此,您可以使用“异步”请求,而不必使用同步请求,而只需在请求完成后执行代码即可。 So, it won't freeze your browser. 因此,它不会冻结您的浏览器。

In the upcoming ECMAScript 2016 (ES7) standard, there is a new set of language keywords designed to do something very similar to what you seem to be looking for, called async and await . 在即将到来的ECMAScript 2016(ES7)标准中,提供了一组新的语言关键字,这些关键字旨在执行与您似乎正在寻找的非常相似的操作,称为asyncawait

These keywords don't allow "non-blocking synchronous AJAX", but they do allow you to write asynchronous code in a way that looks synchronous. 这些关键字不允许 “非阻塞同步AJAX”,但他们让你在看起来同步的方式写异步代码。 Here's a quick example: 这是一个简单的示例:

// Let's say you have an asynchronous function that you want to call in a synchronous
// style...
function delayedEval(delay, func) {
  // First, ensure that the function returns a Promise object. If it doesn't, wrap it with
  // another function that does.
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(func()), delay)
  })
  // For more on Promises, see https://goo.gl/uaoDuy (MDN link)
}

// Then, declare a function as asynchronous. This causes it to return a Promise that 
// resolves to its return value, instead of returning its return value directly.
async function delayedHello() {
  // Inside an async function, you can call other async functions like this, which looks
  // very much like a synchronous call (even though it isn't).
  let message = await delayedEval(1500, () => "Hello, world!")
  console.log(message)
}

// This returns (a Promise) immediately, but doesn't print "Hello, world!" until 1.5
// seconds later. (At which point it resolves the Promise.)
delayedHello()

Try in Babel 尝试通天塔

Basically, instead of "synchronous AJAX without the negative side effects", async and await get you asynchronous AJAX without all its negative side effects. 基本上,而不是“无不良副作用同步AJAX”, asyncawait让你异步 AJAX没有所有它的负面效应。 (Messy code with lots of logic for handling callbacks.) (杂乱的代码具有很多用于处理回调的逻辑。)

async and await are part of the "async functions" candidate recommendation in the ES7 standard. asyncawait是ES7标准中“异步功能”候选建议的一部分。

For the reasons outlined in the other answers here, there is no way to perform a synchronous AJAX call without blocking other events in the browser. 由于此处其他答案中概述的原因,无法在不阻止浏览器中其他事件的情况下执行同步AJAX调用。

However, if code complexity is your primary reason for wanting to avoid asynchronous method calls, you may be interested in the Javascript cross-compiler streamline.js , which allows you to write asynchronous method calls as if they were synchronous, and get the same result as if you wrote the call asynchronously. 但是,如果代码复杂度是您希望避免异步方法调用的主要原因,那么您可能会对Javascript交叉编译器streamline.js感兴趣,它使您可以像异步方法调用一样编写异步方法调用,并获得相同的结果就像您异步编写呼叫一样。

From the project's GitHub page: 在项目的GitHub页面上:

streamline.js is a language tool to simplify asynchronous Javascript programming. streamline.js是用于简化异步Javascript编程的语言工具。

Instead of writing hairy code like: 而不是像这样编写冗长的代码:

 function archiveOrders(date, cb) { db.connect(function(err, conn) { if (err) return cb(err); conn.query("select * from orders where date < ?", [date], function(err, orders) { if (err) return cb(err); helper.each(orders, function(order, next) { conn.execute("insert into archivedOrders ...", [order.id, ...], function(err) { if (err) return cb(err); conn.execute("delete from orders where id=?", [order.id], function(err) { if (err) return cb(err); next(); }); }); }, function() { console.log("orders have been archived"); cb(); }); }); }); } 

you write: 你写:

 function archiveOrders(date, _) { var conn = db.connect(_); conn.query("select * from orders where date < ?", [date], _).forEach_(_, function(_, order) { conn.execute("insert into archivedOrders ...", [order.id, ...], _); conn.execute("delete from orders where id=?", [order.id], _); }); console.log("orders have been archived"); } 

and streamline transforms the code and takes care of the callbacks! 简化代码转换并处理回调!

No control flow APIs to learn! 无需学习控制流API! You just have to follow a simple rule: 您只需要遵循一个简单的规则:

Replace all callbacks by an underscore and write your code as if all functions were synchronous. 用下划线替换所有回调,然后像编写所有函数一样编写代码。

For more information on streamline.js, read the blog post Asynchronous Javascript – the tale of Harry . 有关streamline.js的更多信息,请阅读博客文章Asynchronous Javascript – Harry的故事

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM