使用setTimeout和递归查看某些内容是否“准备就绪”?

时间:2014-03-01 22:37:25

标签: javascript jquery

我正试图找出一种检查某些异步调用是否“准备就绪”的好方法。我有一些运行$ .ajax的函数,并且在回调函数中将全局范围内的布尔变量设置为true(以及其他一些东西)。在ajax调用之前,该布尔变量为false。

我想要另一个检索“其他东西”的函数。由于ajax调用是异步的,显然我不能立即去检索它,因为它可能还不存在。这就是这个布尔变量的来源。我想我可以检查每100毫秒布尔值是否为真,当它出现时,然后检索并返回“其他东西”。

代码方面,它看起来像这样:

window.FOO = window.FOO || {};

;(function() {
    var isReady = false;
    var stuff;

    $.ajax({
        ...
        success: function(data) {
            stuff = data;
            isReady = true;
        }
    })

    FOO.getStuff = function() {
        // How to check if it's "ready"?
    };
}

... (somewhere else)...

var stuff = FOO.getStuff();

我已经尝试了以下FOO.getStuff无效,因为(我认为)setTimeout是异步的:

FOO.getStuff = function() {
    if (isReady) {
        return stuff;
    }
    var theStuff;
    setTimeout(function() {
        theStuff = FOO.getStuff();
    }, 100);
    return theStuff;
};

使用控制台,我可以看到它正在做正确的事情......但是第一个FOO.getStuff调用会在后续调用之前返回。

有更好的方法吗?

编辑:为了澄清,我希望ajax调用保持异步。我完全可以使用同步的getStuff()调用,因为ajax调用会非常快,并且在大多数情况下,getStuff()将在稍后调用(在使用后执行某些操作)。

2 个答案:

答案 0 :(得分:1)

根据你的意见,我有你的答案。要解决异步问题,我们应该执行异步操作。

var stuff;
var stuffQueue = [];
$.ajax({
    success: function(data) {
        stuff = data;
        if( stuffQueue.length > 0 ){
           for(var i in stuffQueue){
              var callback = stuffQueue[i];
              callback(stuff);
           }
           stuffQueue = [];
        } 
    }
});

function getStuff(callback){
   //stuff has been loaded?
   if( stuff ){
     callback(stuff);
   }else{
      stuffQueue.push(callback);
   }
}

要调用内容:

var something = getStuff(function(stuff){
  console.log(stuff);
});

这应该可以解决您的使用案例。让我告诉你更多信息,我有一个JavaScript模板引擎,还没有开源,但我一直在专业项目中使用,我只用一个HTTP请求加载所有模板,我发出请求async:false因为它是一个项目的依赖性。

有些读法说异步虚假是邪恶的,我不相信,邪恶就是用错了。加载模板文件主文件是async:false可以工作的一个很好的例子。

另外,我建议你阅读有关promisses: http://www.html5rocks.com/en/tutorials/es6/promises/

答案 1 :(得分:0)

与Daniel Aranda有类似的想法,我建议你使用自定义事件。

var isReady = true;

$.ajax({
    beforeSend: function() {
        isReady = false;
    },

    success: function(data) {
        isReady = true;
        $(document).trigger('display-stuff', data);
    }
});

Foo.getStuff = function(data) {
    if (!isReady) {
        $(document).one('display-stuff', Foo.getStuff);
        return;
    }

    // do something
};