1

データの特定の変更についてサーバーにpingを実行するこの関数があります。

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

(明らかに、私の意図を明確にするために、コードは最小限に抑えられています)

私がやりたいのは、ブール値が見つかったときにtrueを返すことです。これにより、移動できます。

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

(明らかに、データはグローバル変数に格納されます。)

これを達成する方法はありますか?

編集

'pause'関数を作成できます:

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

しかし、これは少しハッキーな感じがします!

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

対象のブラウザーがJavaScript1.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どこにでもあるすべてに注意してください。これは魔法の一部です。yield呼び出すときとconnectすべての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値を返すことはできなくなったことに注意する必要があります。run2番目の引数を取ることができます:同期関数が完了したときに呼び出されるコールバック。main(たとえば、、、、1および2)に引数を渡すに3は、次のように呼び出します。

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

コールバックが必要ない場合は、nullまたはを渡しundefinedます。


これを試すにtypeは、scriptタグのをに設定する必要がありますtext/javascript; version=1.7。JavaScript 1.7は(のような)新しいキーワードを追加するyieldため、下位互換性がなく、したがって、古いコードと区別するための何らかの方法が必要です。

ジェネレーターの詳細については、MDNのこのページを参照してください。コルーチンの詳細については、ウィキペディアの記事を参照してください。

とはいえ、JavaScript 1.7のサポートが限られているため、これは実用的ではありません。さらに、この種のコードを見るのは一般的ではないため、理解して維持するのが難しい場合があります。Deisssの回答に示されているように、非同期スタイルを使用することをお勧めします。ただし、これが可能であることは素晴らしいことです。

于 2012-07-02T00:15:15.390 に答える