Skip to content

Instantly share code, notes, and snippets.

@dzenkovich
Created October 21, 2013 07:43
Show Gist options
  • Save dzenkovich/7080013 to your computer and use it in GitHub Desktop.
Save dzenkovich/7080013 to your computer and use it in GitHub Desktop.
JS Core: Task 5. Requests Queue.
/**
* This self-invoking anonymous function consists of:
* - onload finction, which cotains functions that are responsible for the logic of click event handling on the Switch button
* - the helper function for adding event listeners;
* - the RequestsQueue constructor: impelements the dymanic queue
*
* It encloses variables and functions in it's scope and helps us keep them out of Global
* This is the most simple scenario of Module pattern.
*
* Working process: by clicking the button on the page, the requests start generating. The amount of requests in the bunch is a random number (from 1 to 3).
* The requests go into the queue until the Stop button is clicked.
* To return SUCCESSFUL responses the folder with the files should be placed on the server
*/
(function(){
/**
* Helper function to create event listeners
* @param element - DOM object that is the event target
* @param event - a string representing the event type to listen for
* @param func - the event listener function that is called when the event occurs
*/
function addEvents(element, event, func){
if(element.addEventListener)
{
element.addEventListener(event, func, false);
}
else if(element.attachEvent)
{
element.attachEvent('on' + event, func); //IE browser
}
}
/**
* Constructor function which describes the queue and its working process of adding/removing requests
* @constructor
*/
function RequestsQueue () {
var self = this, //this variable is created to use the RequestsQueue object reference in the inner function
url = 'response.json',
queueElementsList = [], //the array which contains the incoming requests
states = {
free: 'free',
busy: 'busy'
},
queueState = states.free, // default state of the queue, when the page is loaded
resultBox = document.createElement('div'), // the DOM element which contains the results of the requests and responses
currentListItem;
/**
* Checks the ready state of the response and returns the function which include 2 other functions of processing the responses.
* _processSingleResponse - function that prepares the results for one response
* _processBunchResponse - function that prepares the results for the whole bunch
* @param arrXhr - the array of XHR requests
* @param index - the sequence number of the processing request in the array
* @returns {Function}
* @private
*/
function _processResponse(arrXhr, index) {
return function() {
if(arrXhr[index].readyState === 4) { //checks if the request object doesn't exist or if it ready state is not equal to 4 (4 means that the request finished and response is ready)
//processing for one request
_processSingleResponse(arrXhr, index);
// processing if all xhr's are completed
_processBunchResponse(arrXhr);
}
}
}
/** Creates AJAX requests
* Sends requests for the processing
* @private
*/
function _sendRequestBunch() {
var xhrArray = [], // the array for the requsts
requestsAmount = queueElementsList[0]; //takes the value always from the 1st element with the index 0 from "queueElementsList" variable as a queue is a First-In-First-Out (FIFO) data structure
//creates the LI element, appends it to the OL element and writes the information of the amount of requsts
currentListItem = document.createElement('li');
resultBox.getElementsByTagName('ol')[0].appendChild(currentListItem);
currentListItem.innerHTML = 'Requests amount: ' + requestsAmount + '<br/>';
for(var i = 0; i < requestsAmount; i++) {
xhrArray[i] = new XMLHttpRequest(); //the XMLHttpRequest object is used to exchange data with a server without having to do a full page refresh
xhrArray[i].open('POST', url, true); //specifies the type of request (POST/GET), the URL, and if the request should be handled asynchronously or not
xhrArray[i].onreadystatechange = _processResponse(xhrArray, i); //stores a function which is called automatically each time the readyState property changes (it changes from 0 to 4)
xhrArray[i].send(null); //sends the request to the server, null means that no parameters are sending to the server
}
}
/**
* Processes one response and writes the result to the DOM element
* @param arrXhr - the array of XHR requests
* @param arrIndex - the sequence number of the processing request in the array
* @private
*/
function _processSingleResponse(arrXhr, arrIndex) {
var statusText,
spanElement;
if (arrXhr[arrIndex].status === 200) { //checks if the status is success (status is 200 for a successful request)
statusText = 'Single response status: 200 <br/>';
}
else {// if response failed
statusText = 'Single response status: NOT 200 <br/>';
}
spanElement = document.createElement('span');
spanElement.innerHTML = statusText;
currentListItem.appendChild(spanElement);
}
/**
* Processes a bunch of responses and writes the result to the DOM element
* @param arrXhr - the array of XHR requests
* @private
*/
function _processBunchResponse(arrXhr) {
var isAllComplete = true, // boolean variable which shows if all requests are completed
isAllCompleteSucc = true, // boolean variable which show if all requests are successful
requestsAmountInBunch = arrXhr.length, // the amount of requests in the bunch
statusText, spanElement;
//loops through the items in the array
for (var i = 0; i < requestsAmountInBunch; i++) {
if( (!arrXhr[i]) || (arrXhr[i].readyState !== 4)) { //checks if the request object doesn't exist or if it ready state is not equal to 4 (4 means that the request finished and response is ready)
isAllComplete=false;
break; //breaks the loop and continues executing the code after the loop
}
}
if(isAllComplete) {
for(var i = 0; i < requestsAmountInBunch; i++) {
if(arrXhr[i].status !== 200) { //checks the status of a request
isAllCompleteSucc = false;
break;
}
}
queueElementsList.shift(); //removes the first item of the array
queueState = states.free; //sets the status of the queue to free
//sets the status of the bunch of requests
if(isAllCompleteSucc) {
statusText = 'All SUCCESS';
}
else {
statusText = 'All not SUCCESS';
}
spanElement = document.createElement('span');
spanElement.innerHTML = statusText;
currentListItem.appendChild(spanElement);
//if the queue is free and not empty it continues sending requests for processing
if ((queueState === states.free) && (queueElementsList.length)) {
queueState = states.busy;
_sendRequestBunch();
}
}
}
/**
* Runs on creating a new object
* @private
*/
function _create() {
resultBox.className = 'result'; //adds class name to the DOM element for results of requests
resultBox.appendChild(document.createElement('ol')); // creates element ol and inserts it into the result box
document.body.appendChild(resultBox); // appends the result box to the body element
}
/**
* Adds a new element to the array of requests, checks the state of the queue and if the queue is free and not empty it sends the request (bunch of requests) for the processing
* @param amount - the amount of the AJAX requests
*/
this.addToQueue = function(amount) {
queueElementsList.push(amount); //adds a new request to the array
if ((queueState === states.free) && (queueElementsList.length)) { //checks if the queue is not processing anything and if the queue contains elements
queueState = states.busy; //changes the state of the queue from free to busy
_sendRequestBunch(); //sends the request/request bunch for processing
}
}
_create();
}
/**
* Runs when the DOM is loaded
*/
function onload() {
var switchButton = document.getElementById('switchButton'), //gets the button element from the DOM, this button switches the queue entry of requests
buttonText = {
start: 'START sending requests',
stop: 'STOP sending requests'
},
intervalId, // unique interval ID
intervalTime = 2000, // interval of adding requests to the queue
maxRequestsNumber = 3, // max amount of requests in a bunch
queue = new RequestsQueue(); //creats a new queue object
switchButton.setAttribute('data-switch', 'start'); //sets data-switch attribute to the 'start' value as when the page is loaded only "start" action may be done
switchButton.innerHTML = buttonText.start; //sets text for the switch button
/**
* Starts sending requests to the queue
*/
function startRequests(){
var requestsNumber;
intervalId = setInterval(function(){ //initializes the interval for adding requests to the queue
requestsNumber = Math.floor((Math.random()*maxRequestsNumber) + 1); //gets the random integer number from 1 to the value of max amount of requests
queue.addToQueue(requestsNumber);// adds the requests to the queue
}, intervalTime);
}
/**
* Stops sending requests to the queue
*/
function stopRequests() {
clearInterval(intervalId); //cancels repeated adding of requests to the queue
}
/**
* Toggles the state of the switch button
*/
function toggleButton () {
if (switchButton.getAttribute('data-switch') === 'start') {
startRequests(); //start sending requests
switchButton.setAttribute('data-switch', 'stop');
switchButton.innerHTML = buttonText.stop;
}
else {
stopRequests(); //stop sending requests
switchButton.setAttribute('data-switch', 'start');
switchButton.innerHTML = buttonText.start;
}
}
addEvents(switchButton, 'click', toggleButton);
}
addEvents(window, 'load', onload);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment