2016-05-13 3 views
1

私はonreadystatechange AJAX呼び出しから値を返そうとしています...このページ:stackoverflow linkを見つけました。私はそれを働かせましたが、fn関数を追加したり削除したりすることに違いがないことに気付きました。次のコードは動作します:コールバック付きのonreadystatechangeからの戻り値

username_is_available(); 

function username_is_available() { 
    var username = document.getElementById('username').value; 

    get_data('username', username, function(returned_value) { 
    if (returned_value == 'true') { 
    document.getElementById('username_err').innerHTML = 'Taken'; 
    } else { 
    document.getElementById('username_err').innerHTML = 'Available'; 
    }; 
    }); 
} 

function get_data(data_type, data, fn) { 
    var xmlhttp = new XMLHttpRequest(); 
    xmlhttp.onreadystatechange = function() { 
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 
    fn(xmlhttp.responseText); 
    } 
}; 
    xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true); 
    xmlhttp.send(); 
} 

それはすべてが正常に動作しますが、それが私の目標ではないですが、私は、ユーザー名が実際に利用可能である場合はtrueを返す関数username_is_availableを()したいと思います。 代わりに、ここで私はアクションが起こります(innerHTMLが変更されます)。そして、私が無名関数でリターンしようとすると、私はonreadystatechangeの中から直接返されたのと同じ結果になります:var unasigned

'duplicate thread'をクリックしようとしている人にとって、これはisn重複しない。 私は、ユーザー名が取られているかどうかを判断するためのプロセスが非同期であるため、単純に関数呼び出しからtrueまたはfalseの値を返す方法はありません、少なくとも5時間残念なことに

答えて

2

のためにそれをしてきました。あなたができることは、この正確な目的のために特別に設計された言語機能を使用して、あなたが現在持っているもの(コールバック)と同様のものを設定します。

Promiseは、これらの機能の1つです。

使い方はおおよそ次のようになります:

function username_is_available(username) { 
    return new Promise(resolve => { 
     get_data("username", username, resolve); 
    }); 
} 

function get_data(data_type, data, fn) { 
    var xmlhttp = new XMLHttpRequest(); 
    xmlhttp.onreadystatechange = function() { 
     if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 
      fn(xmlhttp.responseText == "true"); 
     } 
    }; 
    xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true); 
    xmlhttp.send(); 
} 

// Usage: 
username_is_available("Ivan").then(available => { 
    let text = available ? "Available" : "Taken"; 
    document.getElementById("username_err").innerHTML = text; 
}); 

これはresolveが呼び出される前に、ブール値に変換されたテキストとしてtruefalseを返すavailablity.phpに依存しています。将来で

ES7 + asyncawaitディレクティブが用意されていたときに、約束を使用すると、このような単純なものだろう(awaitキーワードを注意してください):

let available = await username_is_available("Ivan"); 
let text = available ? "Available" : "Taken"; 
document.getElementById("username_err").innerHTML = text; 

編集 :あなたがES6や約束を使うことができないなら、それは良いオールコールバックに戻ります!

function username_is_available(username, callback) { 
    get_data("username", username, callback); 
} 

function get_data(data_type, data, fn) { 
    var xmlhttp = new XMLHttpRequest(); 
    xmlhttp.onreadystatechange = function() { 
     if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 
      fn(xmlhttp.responseText == "true"); 
     } 
    }; 
    xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true); 
    xmlhttp.send(); 
} 

// Usage: 
username_is_available("Ivan", function(available) { 
    var text = available ? "Available" : "Taken"; 
    document.getElementById("username_err").innerHTML = text; 
}); 
+1

あなたの最後の例では、 'taken'は' available'でなければならないと思います。 –

+0

'taken'に値を割り当て、宣言されていない変数' available'を使用します。変数名 'taken'は' is_available'というフレーズを持つ関数からブール値を受け取っているので 'available'でなければなりません。 –

+0

@PatrickRoberts良いキャッチ、私は通常のように適切なエディタと貼り付けではなく、テキストボックスに狂ってコードを書く、最初の話題に巻き込まれました。ありがとう! – Scott

0

私は、約束の代わりにオブザーバーと遊んできました。どのように動作するかを示すためにan example in plnkrを設定しました。私はそれが次のようになり、あなたのケースで考える:Producerコードは再利用可能である

function Producer() { 
    this.listeners = []; 
} 

Producer.prototype.add = function(listener) { 
    this.listeners.push(listener); 
}; 

Producer.prototype.remove = function(listener) { 
    var index = this.listeners.indexOf(listener); 
    this.listeners.splice(index, 1); 
}; 

Producer.prototype.notify = function(message) { 
    this.listeners.forEach(function(listener) { 
     listener.update(message); 
    }); 
}; 

var notifier = new Producer; 

function get_data(data_type, data) { 
    var xmlhttp = new XMLHttpRequest(); 
    xmlhttp.onreadystatechange = function() { 
     if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 
      notifier.notify(xmlhttp.responseText); 
     } 
    }; 
    xmlhttp.open("GET", "availability.php?" + data_type + "=" + data, true); 
    xmlhttp.send(); 
} 

var username_is_available = { 
    update: function(returned_value) { 
     var username = document.getElementById('username').value; 
     if (returned_value == 'true') { 
      document.getElementById('username_err').innerHTML = 'Taken'; 
     } else { 
      document.getElementById('username_err').innerHTML = 'Available'; 
     };   
    } 
} 

notifier.add(username_is_available); 
get_data("username", username); 

注意、あなたが他のAJAX /観測可能な要求のための新しいインスタンスを作成します。

関連する問題