building a stack of JSONP requests
i am building an auto suggest box with wikipedia api and the problem is that the order of updates to DOM
is based on the order of responses retrieved from the server whereas it should actually depend on the order of firing of onkeyup
event.
so if i m looking for Lady Gaga
and i press L
and then a
.now if the response from the request where i am looking for L
comes later than response for La
then DOM
is updated with response of L which should not happen because my most recent input is La
.
Therefore on every onkeyup
event a create a Request
object that has the timestamp of when the request was created(onkeyup
event fired) and store it a global array requests
. also there is global variable lastValidRequest
that stores the timestamp of the last Request
object that actually modified DOM
. In the callback function i check whether a Request
whose timestamp is less than lastValidRequest
and discard those requests because they are old and newer Request
than them has been sent. I have commented the code to my best to make every-thing easily understandable. The code looks like this
<script type="text/javascript">
var requests=new Array(); // array to hold requests
var lastValidRequest=(new Date()).getTime(); // shows the time of the last request whose callback function was called
function cb(data) // calls send method of Request object
{
requests[requests.length-1].send(data); //this is where i m going wrong but i dont know wat to do here
}
function Request(url) //request constructor
{
this.time=(new Date()).getTime(); //time at which request was created
this.url=url+"&callback=cb";
this.node=document.createElement('script');
this.node.src=this.url;
this.ran=false; // indicates whether this request modified the div element's contents,just used for making debuuging easy
return this;
};
Request.prototype.send=function(data) {
if (this.time < lastValidRequest) // check if a newer request has been made
{
this.node.parentNode.removeChild(this.node); // cancel the request
//this.node=null;
}
else // this is the newest request
{
lastValidRequest=this.time; //set lastValidRequest to time of this request
this.ran=true;
var str="";
for(var i=0;i<data[1].length;i++)
str=str+data[1][i]+"</br>";
document.getElementById('content').innerHTML=str;
this.node.parentNode.removeChild(this.node);
}
};开发者_开发百科
window.onload=function()
{
textbox=document.getElementById('search');
textbox.onkeyup=function() {
var text=textbox.value; // text is the query for the GET request
if(text=="")
{
document.getElementById('content').innerHTML="";
return;
}
var url="http://en.wikipedia.org/w/api.php?action=opensearch&search=" +text + "&limit=10&namespace=0&format=json";
requests.push(new Request(url)); // create a new request and add it to the end of the array
document.body.appendChild(requests[requests.length-1].node);
}
}
</script>
there is pastebin
link of this code here
UPDATE
i have figured out how to get away with the wikipedia api
because when it returns a response for a search it also returns the search query. for example if i search for gaga
then the JSON
response returned is this
["gaga",["GaGa","GAGA","Gagarin's Start","Gagauz people","Gagauzia","Gaga","Gagaku","Gagauz language","Gagarin","Gagan Narang"]]
now i can easily figure out which response belongs to which request. So i can do something like this to see if the response is for the most recent request
if (textbox.value==data[0]) //check if searchbox's value is same as JSON's first element
{
//update dom because response its for latest request
}
but the exact thing i am looking for is
HOW DO I ASSOCIATE A REQUEST WITH A RESPONSE IN GENERAL?
that is how do i decide which response belongs to which request (am i over hypothesizing?)
What you need to do is to only allow one connection at a time by aborting the previous one.
Unfortunately, I didn't understand your code well enough to see how this is done, but with regular AJAX and jQuery, it would look like:
<script type="text/javascript">
$(document).ready(function(){
var curr_request=null;
$('#autosuggest').keyup(function(){
// abort existing request
if(curr_request)curr_request.abort();
// do the request
curr_request = $.getJSON(the_url,function(data){
curr_request=null;
// populate autosuggest with data
});
});
});
</script>
Edit: Since you're dealing with JSONP, to "abort" a request, you would probably have to remove the script node from the document. Something like document.body.removeChild(requests[requests.length-1].node);
If so, you don't need to keep a stack as well, just keep track of the last one, as I did with curr_request
in my example.
精彩评论