2016-05-13 88 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(); 
} 

這一切工作正常,但是這不是我的目標,我想一個函數username_is_available()如果用戶名確實可以返回true。 相反,在這裏我發生了一個動作(innerHTML被改變)。如果我嘗試在匿名函數中進行返回,則會得到與直接在onreadystatechange中返回結果相同的結果:var unasigned

對於那些即將點擊'重複線程'的人,此isn重複的。 我一直在它5小時以上

回答

2

不幸的是,由於該過程,以確定是否採取了用戶名是異步的,沒有辦法簡單地從函數調用返回的truefalse的值。你所能做的就是使用專門爲此目的設計的語言特性來設置類似於你現在所擁有的東西(回調)。

A Promise是這些功能之一。

用法將看起來大致是這樣的:

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

這依賴於availablity.php返回truefalse爲文本,這是resolve調用之前轉換爲布爾。

今後,當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'應該是'available',因爲它從一個函數中接收一個布爾值,其中包含短語'is_available'。 –

+0

@PatrickRoberts良好的發現,我被抓住了第一個答案的嗡嗡聲,瘋狂地在文本框中編寫代碼,而不是像我平時所做的那樣編寫適當的編輯器和粘貼。謝謝! – Scott

0

我一直在與觀察員一起玩耍,作爲承諾的替代方案。我建立了一個an example in plnkr來展示它如何工作。我想在你的情況是這樣的:

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

注意Producer代碼可以重複使用,你會做一個新的實例爲其他Ajax /觀察到的請求。