JavaScript设置超时循环返回值

时间:2012-07-01 23:13:58

标签: javascript settimeout

我有这个功能,它会ping我的服务器以进行特定的数据更改:

function connected() {
  $.ajax({
    success : function(d) {
      if (d.success) {
        // return data
      } else {
        setTimeout(connected, 200);
      }
    }
  });
}

(显然,代码已被剥离到最低限度,以使我的意图更清晰)

我想要做的是在找到bool时返回true,所以我可以去

if (connected()) {
  // process data
}

(显然数据存储在全局变量中。)

有没有办法实现这个目标?

修改

我可以创建一个'暂停'功能:

function pauseScript(ms) {
  ms += new Date().getTime();
  while (new Date().getTime() < ms) {}
}

然后更改我的代码以排除setTimeout()(并包含其他一些东西)

function connected() {
  var value;
  $.ajax({
    async: false,
    success : function(d) {
      if (d.success) {
        // set data
          value = true;
      } else {
        pauseScript(200);
        value = connected();
      }
    }
  });
  return value;
}

然而这感觉有点hacky!

2 个答案:

答案 0 :(得分:2)

为此,最佳应该在异步模式下继续:

function connected(callback) {
  $.ajax({
    success : function(d) {
      if (d.success) {
        callback();
      } else {
        setTimeout(function() {
          connected(callback);
        }, 200);
      }
    }
  });
}

//Using :
connected(function(){
  //Here i finish my scan result
});

也许,我不太确定在这种情况下,你需要绑定它(我的意思是绑定范围): http://www.robertsosinski.com/2009/04/28/binding-scope-in-javascript/

答案 1 :(得分:1)

如果您定位的浏览器支持JavaScript 1.7或更高版本(在撰写本文时,我认为只有Gecko浏览器可以),那么您可以利用生成器来执行此操作。让我们首先让你的connect函数异步(并且更容易进行测试):

function connectAsync(callback) {
    // Pretend we always succeed after a second.
    // You could use some other asynchronous code instead.
    setTimeout(callback, 1000, true);
}

现在将您的调用代码包装到一个函数中。 (它必须是一个函数。)

function main() {
    console.log("Connecting...");
    if(!(yield connect())) {
        console.log("Failed to connect.");
        yield; return;
    }
    console.log("Connected.");
    yield;
}

注意所有yield到处都是。这是魔术的一部分。当我们在每个函数退出点之前调用yieldconnect时,我们需要yield

现在我们需要定义connect。你可能想要同步一堆异步函数,所以让我们创建一个使函数同步的函数。

function synchronize(async) {
    return function synchronous() {
        return {func: async, args: arguments};
    };
}

然后我们可以用connect创建connectAsync

var connect = synchronize(connectAsync);

现在我们需要创建一个运行所有这些魔法的函数。这是:

function run(sync) {
    var args = Array.prototype.slice.call(arguments);
    var runCallback = args.length ? args[args.length - 1] : null;
    if(args.length) {
        args.splice(args.length - 1, 1);
    }
    var generator = sync.apply(window, args);
    runInternal(generator.next());
    function runInternal(value) {
        if(typeof value === 'undefined') {
            if(runCallback) {
                return runCallback();
            }else{
                return;
            }
        }
        function callback(result) {
            return runInternal(generator.send(result));
        }
        var args = Array.prototype.slice.call(value.args);
        args.push(callback);
        value.func.apply(window, args);
    }
}

现在,您可以使用此魔法运行main函数:

run(main);

我应该注意main不再可以返回值。 run可以采用第二个参数:在同步函数完成时调用的回调。要将参数传递给main(例如123),您可以这样称呼:

run(main, 1, 2, 3, callback);

如果您不想收回回复,请传递nullundefined


要尝试此操作,您必须将type标记的script设置为text/javascript; version=1.7。 JavaScript 1.7添加了新的关键字(如yield),因此它是向后兼容的,因此必须有一些方法可以将自己与旧代码区分开来。

有关生成器的更多信息,请参阅this page on MDN。有关协同程序的更多信息,请参阅the article on Wikipedia

由于JavaScript 1.7的支持有限,所有这些都说不实用。此外,看到这种代码并不常见,因此可能难以理解和维护。 我建议只使用异步样式,如Deisss's answer中所示。然而,它是可能这样做很好。