无阻塞同步AJAX



有没有一种方法可以执行不冻结浏览器的同步AJAX查询?在我看来,在大多数情况下,同步请求更容易处理,但它们阻止代码的其他部分执行的事实是一个真正的杀手。有没有一种方法可以在没有负面影响的情况下获得同步AJAX?(是的,我意识到术语"同步AJAX"是一种矛盾修辞法。)

我将提供一个允许这种行为的不良影响的例子。

假设你有这个程序:

<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>

这里的坏事-

  • synchronousLoad()阻塞5秒时,用户单击按钮,事件处理程序快速运行到完成
  • 现在file变量为空
  • synchronousLoad()完成并返回,让下一行代码继续执行
  • 但是file现在为空并且向用户输出的消息被破坏

这里真正的问题是,你不能再以同样的方式推理你的代码了。只是因为一些事实第5行为true,并不意味着下一行仍然为true。这使得编写一个没有错误的程序变得非常困难。

有些编程语言支持多线程,您必须处理这些问题,尽管您有工具可以帮助处理这些问题。但是,程序员仍然需要付出很多额外的努力。

相比之下,使用回调进行异步操作是ez模式。

否。根据定义,同步就是阻塞。在流程完成之前,任何操作都无法继续。这包括web浏览器中UI的其余部分。

假设是异步的,所以最好的方法是将代码设计为异步工作。

在即将推出的ECMAScript 2016(ES7)标准中,有一组新的语言关键字被设计用于做与您想要的非常相似的事情,称为asyncawait

这些关键字不允许";非阻塞同步AJAX";,但它们确实允许您以看起来同步的方式编写异步代码。这里有一个快速的例子:

// 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://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
}
// 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()

试用Babel

基本上;没有负面副作用的同步AJAX";,asyncawait可以让您异步AJAX,而不会产生任何负面影响。(带有大量处理回调逻辑的混乱代码。)

CCD_ 9和CCD_;异步函数";ES7标准中的候选人推荐。

我认为这是不可能的。您可以使用异步方法并使用AJAX done事件,而不是尝试使用同步查询。

使用jQuery.ajax()的示例

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

因此,您可以使用异步请求,并在请求完成后执行代码,而不是使用同步请求。所以,它不会冻结你的浏览器。

由于此处其他答案中列出的原因,无法在不阻止浏览器中其他事件的情况下执行同步AJAX调用。

但是,如果代码复杂性是您想要避免异步方法调用的主要原因,那么您可能会对Javascript跨编译器streamline.js感兴趣,它允许您像编写同步方法调用一样编写异步方法调用,并获得与异步编写调用相同的结果。

来自项目的GitHub页面:

streamline.js是一种简化异步Javascript的语言工具编程。

而不是像那样编写毛茸茸的代码

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();
      });
    });
  });
}

你写:

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");
}

和流线型转换代码并处理回调!

无需学习控制流API!你只需要遵循一个简单的规则:

用下划线替换所有回调,并将代码写成功能是同步的。

有关streamline.js的更多信息,请阅读博客文章Asynchronous Javascript——哈利的故事。

最新更新