1

我有这个功能可以 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!

4

2 回答 2

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/

于 2012-07-01T23:26:27.400 回答
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地方的所有 s。这是魔法的一部分。我们yield在调用时需要connect一个,yield在每个函数退出点之前都需要一个。

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

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

然后我们可以connectconnectAsync它创建:

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),因此它是向后不兼容的,因此,必须有某种方式将自己与旧代码区分开来。

有关生成器的更多信息,请参阅MDN 上的此页面。有关协程的更多信息,请参阅Wikipedia 上的文章

尽管如此,由于对 JavaScript 1.7 的支持有限,这并不实用。此外,这种代码并不常见,因此可能难以理解和维护。我建议只使用异步风格,如Deisss 的回答所示但是,可以做到这一点很巧妙。

于 2012-07-02T00:15:15.390 回答