Skip to content

Instantly share code, notes, and snippets.

@kyo-ago
Created August 29, 2012 09:14
Show Gist options
  • Save kyo-ago/3508901 to your computer and use it in GitHub Desktop.
Save kyo-ago/3508901 to your computer and use it in GitHub Desktop.
JavaScript request controler(start, stop, restart)
request.responseError = request.offlineError = request.timeoutError = function () {
request.callQueue('stop');
alert('Network error\nDo you want to reconnect?');
$('<button id="ok">ok</button><button id="cancel">cancel</button>').appendTo('body')
.find('#ok').click(function () {
request.callQueue('restart');
}).end()
.find('#cancel').click(function () {
request.callQueue('abort');
}).end()
;
}
(function () {
var old_ajax = $.ajax;
$.ajax = function (options) {
var self = this;
var xhr;
var aborted = function () {
xhr && xhr.abort();
};
request.add(function (callback) {
options.success = callback.success;
options.error = callback.error;
xhr = old_ajax.call(self, options);
}, success, aborted, function () {
self.ajax(options);
});
return aborted;
};
})();
var request = {
// global response error
'responseError' : function (xhr_status) {
},
// global offline error
'offlineError' : function () {
},
// global timeout error
'timeoutError' : function () {
},
// make id counter
'counter' : 0,
// current request queue
'queue' : {},
// call queue function
'callQueue' : function (name) {
var keys = Object.keys(this.queue);
for (var i = 0, l = keys.length; i < l; ++i) {
var key = keys[i];
var obj = this.queue[key];
obj && obj[name] && obj[name]();
}
},
// clear all queue
'clearQueue' : function () {
this.counter = 0;
this.queue = {};
},
// stop all request
'stopQueue' : function () {
var keys = Object.keys(this.queue);
for (var i = 0, l = keys.length; i < l; ++i) {
var key = keys[i];
var obj = this.queue[key];
if (!obj) {
continue;
}
obj['connectTimeout'] && clearTimeout(obj['connectTimeout']);
obj['sendTimeout'] && clearTimeout(obj['sendTimeout']);
delete obj['connectTimeout'];
delete obj['sendTimeout'];
}
},
// request timeout
'timeout' : 15 * 1000,
// for UnitTest
'navigator' : navigator,
'add' : function (send, success, abort, restart) {
var self = this;
var queue_id = this.counter++;
var state = {
'restart' : function () {
delete self.queue[queue_id];
restart();
},
'stop' : abort,
'abort' : function () {
delete self.queue[queue_id];
abort();
},
'connectTimeout' : '',
'sendTimeout' : ''
};
// this.queue is object(not array)
this.queue[queue_id + ''] = state;
state['connectTimeout'] = setTimeout(function () {
delete state['connectTimeout'];
self.stopQueue();
abort();
self.timeoutError();
}, this.timeout);
state['sendTimeout'] = setTimeout(function () {
if (!self.navigator.onLine) { // for UnitTest
self.stopQueue();
self.offlineError();
self.navigator.onLine = true;
return;
}
send({
'error' : function (xhr) {
self.stopQueue();
self.responseError(xhr.status);
},
'success' : function (json, xhr) {
clearTimeout(state['connectTimeout']);
delete self.queue[queue_id];
success(json, xhr);
}
});
});
}
};
TestCase('request', {
'setUp' : function () {
this.clock = sinon.useFakeTimers();
},
'_init_request' : function () {
var req = {};
req.request = function (success, error) {
var timeout = setTimeout(function () {
if (!req.request.error) {
success();
} else {
error({
'status' : 200
});
}
});
return function () {
clearTimeout(timeout);
};
};
req.request.error = false;
request.responseError = this.stub();
request.offlineError = this.stub();
request.timeoutError = this.stub();
request.clearQueue();
return req;
},
'_make_connection' : function (req) {
var self = this;
var conn = {};
var abort;
conn.aborted = this.spy(function () {
abort && abort();
});
conn.send = this.spy(function (callback) {
abort = self.spy(req.request(self.spy(callback.success), self.spy(callback.error)));
});
conn.success = this.stub();
conn.restart = this.stub();
return conn;
},
'test10_request_success' : function () {
var self = this;
var req = self._init_request();
var conn = self._make_connection(req);
request.add(conn.send, conn.success, conn.aborted, conn.restart);
this.clock.tick(100);
assertCalledOnce(conn.send);
assertCalledOnce(conn.success);
},
'test10_request_error' : function () {
var self = this;
var req = self._init_request();
var conn = self._make_connection(req);
req.request.error = true;
request.add(conn.send, conn.success, conn.aborted, conn.restart);
this.clock.tick(100);
assertCalledOnce(request.responseError);
},
'test10_request_error_abort' : function () {
var self = this;
var req = self._init_request();
var conn_a = self._make_connection(req);
var conn_b = self._make_connection(req);
request.responseError = this.spy(function () {
request.callQueue('abort');
});
req.request.error = true;
request.add(conn_a.send, conn_a.success, conn_a.aborted, conn_a.restart);
request.add(conn_b.send, conn_b.success, conn_b.aborted, conn_b.restart);
this.clock.tick(100);
assertNotCalled(conn_a.success);
assertNotCalled(conn_b.success);
assertCalledOnce(conn_a.aborted);
assertCalledOnce(conn_b.aborted);
assertCalledOnce(request.responseError);
assertEquals(request.queue, {});
},
'test10_request_error_redo' : function () {
var self = this;
var req = self._init_request();
var conn_a = self._make_connection(req);
var conn_b = self._make_connection(req);
request.responseError = this.spy(function () {
request.callQueue('restart');
});
req.request.error = true;
request.add(conn_a.send, conn_a.success, conn_a.aborted, conn_a.restart);
request.add(conn_b.send, conn_b.success, conn_b.aborted, conn_b.restart);
this.clock.tick(100);
assertNotCalled(conn_a.success);
assertNotCalled(conn_b.success);
assertCalledOnce(conn_a.restart);
assertCalledOnce(conn_b.restart);
assertCalledOnce(request.responseError);
assertEquals(request.queue, {});
},
'test10_request_error_restop' : function () {
var self = this;
var req = self._init_request();
var conn_a = self._make_connection(req);
var conn_b = self._make_connection(req);
request.responseError = this.spy(function () {
request.callQueue('stop');
setTimeout(function () {
request.callQueue('restart');
});
});
req.request.error = true;
request.add(conn_a.send, conn_a.success, conn_a.aborted, conn_a.restart);
request.add(conn_b.send, conn_b.success, conn_b.aborted, conn_b.restart);
this.clock.tick(100);
assertNotCalled(conn_a.success);
assertNotCalled(conn_b.success);
assertCalledOnce(conn_a.restart);
assertCalledOnce(conn_b.restart);
assertCalledOnce(request.responseError);
assertEquals(request.queue, {});
},
'test10_request_error_offline' : function () {
var self = this;
var req = self._init_request();
var conn_a = self._make_connection(req);
var conn_b = self._make_connection(req);
request.navigator = {
'onLine' : false
};
request.offlineError = this.spy(function () {
request.callQueue('abort');
});
request.add(conn_a.send, conn_a.success, conn_a.aborted, conn_a.restart);
request.add(conn_b.send, conn_b.success, conn_b.aborted, conn_b.restart);
this.clock.tick(100);
assertNotCalled(conn_a.success);
assertNotCalled(conn_b.success);
assertCalledOnce(conn_a.aborted);
assertCalledOnce(conn_b.aborted);
assertCalledOnce(request.offlineError);
assertEquals(request.queue, {});
request.navigator = navigator;
},
'test10_request_error_timeout' : function () {
var self = this;
var req = self._init_request();
req.request = function () {
return function () {};
};
var conn = self._make_connection(req);
request.timeoutError = this.spy(function () {
request.callQueue('abort');
});
request.timeout = 100;
request.add(conn.send, conn.success, conn.aborted, conn.restart);
this.clock.tick(200);
assertNotCalled(conn.success);
assertCalledOnce(request.timeoutError);
assertEquals(request.queue, {});
},
'test10_request_error_timeout_redo' : function () {
var self = this;
var req = self._init_request();
req.request = function () {
return function () {};
};
var conn = self._make_connection(req);
request.timeoutError = this.spy(function () {
request.callQueue('stop');
setTimeout(function () {
request.callQueue('restart');
});
});
request.timeout = 100;
request.add(conn.send, conn.success, conn.aborted, conn.restart);
this.clock.tick(200);
assertCalledOnce(conn.restart);
assertCalledOnce(request.timeoutError);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment