I am noticing a significant difference in speed between plain node.js VS node-webkit
All I'm doing is connecting to a localhost couchdb using the HTTP module.
The same code takes ~520ms to establish a connection and return a response in node-webkit whereas it takes ~10ms in plain node.js
Can someone with more in-depth knowledge of node-webkit help explain what is causing this?
The code is below
Class = new function() {};
Class.prototype.info = function(s) {console.log(console,s);}
Class.prototype.err = function(s) {console.log(console,s);}
Class.prototype.warning = function(s) {console.log(console,s);}
Class.prototype.debug = function(s) {console.log(console,s);}
Class.prototype.postMessage = function(oterm, msg) {
__cb.shift().call(this, msg);
}
Class.prototype.onMsgFor = {};
Class.prototype.__agentkeepalive = require('agentkeepalive');
Class.prototype.__http = require("http");
Class.prototype.__follow = require("follow");
Class.prototype.__http.globalAgent.maxSockets = 1;
Class.prototype._onInit = function(props) {
this._host = props["host"];
this._port = props["port"];
this._db_name = props["name"];
this._agent = new this.__agentkeepalive({
minSockets: 1
,maxSockets: 1
, maxKeepAliveRequests: 0
, maxKeepAliveTime: 300000
});
};
Class.prototype.onMsgFor["connect_request_in"] = function(msg) {
var err;
var self = this;
self._connect(this._host, this._port, this._db_name);
};
/*************************************************************************/
Class.prototype._connect = function(host, port, namespace) {
var self = this;
var err;
function _onConnect(code, body, hdrs) {
function _onCreate(code, body, hdrs) {
if (code == 201) { // created
//self._registerChangeNotification();
self.postMessage("connect_response_out", {name: namespace});
} else {
alert(code);
err = "Unable to create namespace: " + namespace;
self.error(err);
self.postMessage("error_response_out", {text_content:err});
}
}
if (code == undefined) { // no code means error connecting
self.error("Error connecting to DB: " + body);
self.postMessage("error_response_out", {text_content:body
,question: "Is CouchDB up?"});
} else if (code == 200) { // ok
if (body.indexOf(namespace) != -1) {
//self._registerChangeNotification();
self.postMessage("connect_response_out", {name: namespace});
} else {
self.warning("No such namespace: " + namespace);
self._request(host, port, namespace, "PUT", _onCreate);
}
} else {
alert("Unexpected code: " + code);
}
return;
}
self._request( host, port, "_all_dbs", "GET", _onConnect);
};
Class.prototype._request = function(host, port, namespace, method, cb, uuid, arg, opts) {
var t = (new Date()).getTime();
var self = this;
var path = "/" + escape(namespace) + (uuid ? ("/" + escape(uuid)) : "");
var req, k, buf = "", headers = {};
if (method == "POST" || method == "PUT") {
headers["content-type"] = "application/json";
buf = JSON.stringify(arg);
}
if (opts) {
path += "?";
for (k in opts) {
path += k + "=" + opts[k];
}
}
self.info("http://" + host + ":" + port + path);
req = this.__http.request({hostname: host
, port: port
, path: path
, method: method
, headers : headers
, agent: this._agent
});
req.setNoDelay(true)
req.setSocketKeepAlive(true, 0);
function _onError(err) {
cb(undefined, err.message, {});
}
function _onSocket(socket) {
console.log("[SOCKET: " + socket.localPort + "] , " + ((new Date()).getTime() - t) + " , W:" + socket.bytesWritten + " / R:" + socket.bytesRead);
function _onEnd() {
console.log("** END ** ")
}
function _onClose() {
console.log("** CLOSE **");
}
if (!socket.localPort) {
socket.setNoDelay(true)
socket.setKeepAlive(true, 0);
socket.on("end", _onEnd);
socket.on("close", _onClose);
}
}
function _onResponse(response) {
var len = response.headers["content-length"];
var encoding = response.headers["transfer-encoding"];
var payload = "";
console.log(" <<< [RESPONSE: " + response.statusCode+ "] " + (new Date()).getTime() + " , " + ((new Date()).getTime() - t));
function _onEnd() {
switch (response.statusCode) {
case 200: // ok
case 201: // created
try {
payload = JSON.parse(payload || "");
} catch (e) {
self.error("Error parsing payload");
cb(undefined,e.message,{});
return;
/*****************************************************/
}
break;
case 400: // bad request
break;
case 404: // not found
break;
case 409: // conflict
break;
case 415: // Unsupported Media Type
break;
default:
alert("ACK! unknown code: " + response.statusCode);
break;
}
//console.log("PAYLOAD: " + JSON.stringify(payload));
cb(response.statusCode, payload, response.headers);
}
function _onClose() {
console.log(">> CLOSE");
}
function _onData(chunk) {
payload += (chunk || "");
}
self.debug("response returned in (ms): " + ((new Date()).getTime() - t));
// console.log((new Date()).getTime());
response.on("data", _onData);
response.on("end", _onEnd);
response.on("close", _onClose);
}
function _onClose() {
console.log("[CLOSE]");
}
function _onEnd() {
console.log("[END]");
}
req.on("socket", _onSocket);
req.on("response", _onResponse);
req.on("error", _onError);
req.on("close", _onClose);
req.on("end", _onEnd);
console.log(" >>> [REQUEST: " + method + " " + path + "] " + t)
req.end(buf);
}
var __cb = [
function(msg) {
console.log("CONNECTED " + msg);
}
];
var o = new Class();
o._onInit({host: "localhost"
,port: 5984
,name: "stack"});
o.onMsgFor["connect_request_in"].call(o);
thank you
slim
I'm certainly not an expert, but it's probably due to the way they tied the node runtime to the webkit runtime.
Node has a highly optimised, hight streamlined runtime, with only the most necessary running at any one time.
This is not the case in webkit (with regards to server programming at least) as at any moment it will have the rendering engine, any loaded modules/extensions and page scripts the css engine and much more, all churning away.
Check out this link to the Node-Webkit wiki that explains how the runtimes were merged: https://github.com/rogerwang/node-webkit/wiki/How-node.js-is-integrated-with-chromium
Hope this sheds some light!!
Related
I am developing an office 365 word web addin, wherein I need to upload the currently opened document to my server. For which I am trying to get the file data using following code.
The method getSliceAsync() is returning only first slice of data.
On debugging it gives "Addin Error: Sorry, we had to restart because this addin wasn't responding" while getting second slice.
I am using this link for reference : [https://learn.microsoft.com/en-us/office/dev/add-ins/word/get-the-whole-document-from-an-add-in-for-word][1]
Here is my code:
Office.context.document.getFileAsync(Office.FileType.Compressed, { sliceSize: 65536 }, function (result) {
if (result.status == "succeeded") {
// If the getFileAsync call succeeded, then result.value will return a valid File Object
var myFile = result.value;
var filename1 = myFile.name;
console.log(filename1);
var sliceCount = myFile.sliceCount;
var slicesReceived = 0, isAllSlicesSuccess = true, docdataSlices = [];
// document.getElementById("result").innerText = "File size:" + myFile.size + "#Slices: " + sliceCount;
console.log(" File size:" + myFile.size + " #Slices: " + sliceCount, "");
makeProgress(20);
// Iterate over the file slices
for (var i = 0; i < sliceCount && isAllSlicesSuccess; i++) {
var diffPercent = ((i / sliceCount) * 100);
myFile.getSliceAsync(i, function (sliceResult) {
if (sliceResult.status == "succeeded") {
if (!isAllSlicesSuccess) { // Some slice has failed to get, no need to continue
console.log("Error", "One slice failed to get");
return;
console.log(sliceResult);
}
console.log('sliceResult', sliceResult);
console.log("Success", "i: " + i);
console.log("++slicesReceived ",slicesReceived );
console.log(" sliceCount",sliceCount );
console.log("++slicesReceived == sliceCount",slicesReceived == sliceCount);
// One chunk was got, store it in a temporal array
// ++slicesReceived;
// or you can do something with the chunk, such as sent it to a third party server
docdataSlices[sliceResult.value.index] = sliceResult.value.data;
if (++slicesReceived == sliceCount) {
getAllSlicesTime = Date.now();
var performance = (getAllSlicesTime - startTime) / 1000.0;
console.log("Success", "All slices has been get, Seconds: " + performance);
// All slices have been received
myFile.closeAsync(function (closeRes) {
if (closeRes.status == "succeeded") {
console.log("Close Success", "Success");
// DUClick();
}
else {
console.log("Close Error", closeRes.error.message);
}
});
onGetAllSlicesSucceeded(docdataSlices, false);
}
}
else {
isAllSlicesSuccess = false;
myFile.closeAsync(function (closeRes) {
if (closeRes.status == "succeeded") {
console.log("Close Success", "Success");
// DUClick();
}
else {
console.log("Close Error", closeRes.error.message);
}
});
console.log("Get Slice Error:", sliceResult.error.message);
}
});
}
}
else {
getFileTime = Date.now();
var performance = (getFileTime - startTime) / 1000.0;
console.log('Get File Error:', "Seconds: " + performance + " " + result.error.message);
}
});
Please suggest! Thanks in advance!
[1]: https://learn.microsoft.com/en-us/office/dev/add-ins/word/get-the-whole-document-from-an-add-in-for-word
I am requesting a rest server from nodejs by using nodejs request module.
I want to cancel stream if incoming data size is out of allowed limit.the purpose here is to ensure that my network is not locked.
My code example is as follows;
var http = require("http");
async function httpRequest({
host,
method,
port,
path
} = params, data) {
if (method.toUpperCase() === "GET") {
let query = "";
data = JSON.parse(data);
for (var key in data) {
if (data.hasOwnProperty(key)) {
let value = data[key];
console.log(key + " -> " + value);
query = query
.concat("&")
.concat(key)
.concat("=")
.concat(value);
}
}
if (query) {
query = "?".concat(query.substring(1));
}
path = encodeURI(path.concat(query));
console.log("path : " + path);
}
var opts = {
hostname: host,
port: port,
path: path,
method: method,
timeout: 30 * 1000,
headers: {
"Content-Type": "application/json"
}
};
return new Promise(function (resolve, reject) {
const req = http.request(opts, function (response) {
console.log("Status Code : " + response.statusCode);
if (response.statusCode < 200 || response.statusCode >= 300) {
req.end();
return reject("Fetch data failed = " + response.statusCode);
}
var str = "";
response.on("data", function (chunk) {
console.log("chunk : " + chunk);
str += chunk;
if (str.length > 256) {
req.abort();
reject(
new Error(
"The size of the incoming data is larger than the allowable limit."
)
);
}
});
response.on("end", function () {
console.log("\n Result from web service : ", str);
try {
let jsonData = JSON.parse(str);
if (jsonData.status) {
if (jsonData.status.toLowerCase === "success") {
if (!("result" in jsonData)) {
reject("Json Structure Error");
}
} else if (jsonData.status.toLowerCase === "error") {
if (!jsonData.error) {
reject("Json Structure Error");
}
}
resolve(jsonData);
} else {
reject("Json Structure Error");
}
} catch (error) {
reject("Response json error : " + error);
}
});
});
if (method.toUpperCase() !== "GET" && data) {
req.write(data);
}
//req bitti
req.on("timeout", function () {
console.log("timeout! " + opts.timeout / 1000 + " seconds expired");
req.abort();
});
req.on("error", function (err) {
console.log("Error : " + err);
if (err.code === "ECONNRESET") {
req.abort();
console.log("Timeout occurs : " + err);
reject(new Error("Timeout occurs : " + err));
} else if (err.code === "ENOTFOUND") {
req.abort();
console.log("Address cannot be reachable : " + err);
reject(new Error("Address cannot be reachable : " + err));
} else {
req.abort();
reject(new Error(err));
}
});
req.end();
});
}
let data = JSON.stringify({
username: "monetrum",
password: "123456",
name: "Loremipsumdolorsitamet,consecteturadipiscingelit" +
".Aeneaninaliquamodio,egetfac"
});
let params = {
host: "127.0.0.1",
method: "GET",
port: 3010,
path: "/login"
};
httpRequest(params, data);
So farr so good.But There is a problem.I am controlling incoming data.Size of data I allowed must not greater than 256 Bytes.But first fetch of chunk is larger than allowed size.So my size control is nonsense.Is there a way to handle it.Is it possible to limit size of chunk. Thanks in advance.
The 'readable' event
You want to use the readable event instead of the data event:
var byteCount = 0;
var chunkSize = 32;
var maxBytes = 256;
req.on('readable', function () {
var chunks = [];
var data;
while(true) {
data = this.read(chunkSize);
if (!data) { break; }
byteCount += data.byteLength;
if (byteCount > maxBytes) {
req.abort();
break;
}
chunks.push(data);
}
// do something with chunks
});
req.on('abort', function () {
// do something to handle the error
});
Since your question is very specific I made the example a little more generic so that hopefully others will be able to glean from it as well.
See https://nodejs.org/api/stream.html#stream_event_readable
However...
The Network Does't Care
However, you're going to get more data than that. TCP packet size is 64k. Over non-gigabit ethernet that gets MTU truncated to 1500 bytes (1.5k).
There's nothing that you can do to prevent the network activity from happening other than closing the connection, and you can't get less than 1.5k of data per data event unless there is less than 1.5k of data being sent (or crazy network issues happen, which you have no control over).t
P.S.
I'd recommend that you use a code editor, like VSCode. It's very difficult to read code that has mixes of tabs and spaces and different blocks at different levels. It will suggest plugins that can help you catch mistakes earlier and reformat your code so that it's easier for others (and yourself) to read it.
https://code.visualstudio.com/
https://code.visualstudio.com/docs/languages/javascript
https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode
I have got a node js program as below.
msg = "Generate a number......";
sessionAttributes = {};
console.log("Session arreubs are :" + sessionAttributes);
console.log("end of flow");
callback(close(intentRequest.sessionAttributes, "Fulfilled", buildMessage(msg)));
here is my close callback
function close(sessionAttributes, fulfillmentState, message) {
return {
sessionAttributes,
dialogAction: {
type: "Close",
fulfillmentState,
message,
},
};
}
when I run this, I get the output as Generate a number....... But now I need to integrate this with an API call. and the updated code is as below.
var service = require("./service.js");
service.createIncident(enterpriseID, shortDesc,
function (incidentNo) {
if (incidentNo) {
console.log("Index.js ServiceNow Incident:" + incidentNo);
msg = "Thank you! Your " + TicketType + " Number is " + incidentNo;
console.log("end of flow");
callback(close(intentRequest.sessionAttributes, "Fulfilled", buildMessage(msg)));
} else {
console.log("Index.js ServiceNow Incident:" + incidentNo);
msg = "Err";
console.log("end of flow");
callback(close(intentRequest.sessionAttributes, "Fulfilled", buildMessage(msg)));
}
});
console.log("process is done");
my service.js
var request = require("request");
var servicenow = require("./configfile.json");
var snowURL = servicenow.url;
var snowUsername = servicenow.username;
var snowPassword = servicenow.password;
var ticketNo = "00000";
console.log("Service Now URL:" + snowURL + " Username:" + snowUsername + " Password:" + snowPassword);
module.exports.createIncident = function (caller_id, short_description, callback) {
var snowdetails = {
uri: snowURL,
method: "POST",
"content-type": "application/json",
"auth": {
"username": snowUsername,
"password": snowPassword
}
};
request(snowdetails, function (error, resp, body) {
console.log("Status code " + resp.statusCode);
if (!error && (resp.statusCode == 200 || resp.statusCode == 201)) {
if (body) {
var data = JSON.parse(body);
ticketNo = data.result.number;
console.log("Service Now Incident No:" + ticketNo);
callback(ticketNo);
return;
} else {
console.log("I am unable to authenticate you. please disable the skill and re link your account");
callback("I am unable to authenticate you. please disable the skill and re link your account");
}
} else {
console.log(error);
callback(error);
}
});
};
Here when I run this, I get the output as
process is done
Service Now Incident No:INC0010035
Index.js ServiceNow Incident:INC0010035
Thank you! Your incident Number is INC0010035
and in my window, earlier, when there was no callback, it used to print the msg content, i.e. Generating ticket......, but now it is not printing anything.
Where am I going wrong and how can I fix it?
I'm using Node to run this program, where is my error(s)? It's saying I'm missing ) after argument list. I can't find where this error is, I've tried putting the ) in various places. I'm using Node v5
var Twit = require('twit');
var T = new Twit(require('./config.js'));
var stream = T.stream('statuses/filter', {
track: 'xoxo, oi, i\m fine,'
});
(stream.on('tweet', function(tweet) {
console.log('#' + tweet.user.screen_name + ': ' + tweet.text);
if (tweet.text.indexOf('RT') > -1) {
return;
}
var replyString;
if (tweet.user.utc_offset === null) {
replyString = ' Ok';
} else {
replyString = ' Okay';
}
})
(T.post('statuses/update', {
status: '#' + tweet.user.screen_name + replyString,
in_reply_to_status_id: tweet.id_str
}, function(err, data, response) {
if (err) {
console.log(err);
return;
}
}
tweet.botReplyId = data.id_str);
db.tweets.insert(tweet);
});
(end)
})
setInterval(stream, 60000);
The code seems to be a bit all over the place with regards to scope and it makes it a bit difficult to follow.
Try using something like the following which annotates it a bit and should help avoid issues like this (as it seems to validate without any errors) :
// Define your variables
var Twit = require('twit');
var T = new Twit(require('./config.js'));
var stream = T.stream('statuses/filter', { track: 'xoxo, oi, i\'m fine,'});
// When a tweet occurs
(stream.on('tweet', function(tweet) {
// Log it
console.log('#' + tweet.user.screen_name + ': ' + tweet.text);
// Determine if it is a retweet and ignore
if (tweet.text.indexOf('RT') > -1) { return; }
// Set your reply
var replyString = (tweet.user.utc_offset === null) ? ' Ok' : ' Okay';
// Post your reply
T.post('statuses/update', { status: '#' + tweet.user.screen_name + replyString, in_reply_to_status_id: tweet.id_str}, function(err, data, response) {
// If an error occurs, log it
if (err) {
console.log(err);
return;
}
// Otherwise store your response and store it
tweet.botReplyId = data.id_str;
db.tweets.insert(tweet);
});
}));
// Check your stream every 10 minutes
setInterval(stream, 60000);
We are using CrossRider to develop an extension for Internet Explorer. Our extension has code that sends a message to the background, and the background sends a reply and calls a callback function. This works in my computer with Internet Explorer 11, but in my Friend Tom's computer (also with Internet Explorer 11) it doesn't work - the callback is not called in his computer. What is the problem and how do we fix it to work in any computer? Here is the relevant code:
_base.js:
alert("[ContentBase::getData] >>>>>"); // This happens in any computer.
var request = {command: 'get', webmail: thisObj.mContentType, param: param, type: type, contentType: contentType};
thisObj.sendRequest(request, function(response) {
alert("[ContentBase::getData] received data >>>>>"); // This doesn't happen in Tom's computer.
if (typeof(callback) === 'function') {
callback(response);
}
});
utils.js:
this.sendRequest = function(request, callback) {
if (typeof(callback) !== 'function') {
callback = function(response) {};
}
switch (Sys.platform) {
case 'crossrider':
var message = {request: request, message_id: Math.floor((Math.random() * 900000000000000) + 100000000000000)};
if (typeof thisObj.mCallbackMap === 'undefined') {
thisObj.mCallbackMap = {};
appAPI.message.addListener({channel: "message_from_background"}, function(message) {
if (typeof thisObj.mCallbackMap[message.message_id] === 'function') {
thisObj.mCallbackMap[message.message_id](message.response);
delete thisObj.mCallbackMap[message.message_id];
}
});
}
(function(callback_inner) {
thisObj.mCallbackMap[message.message_id] = function(response) {
if (typeof(callback_inner) === 'function') {
callback_inner(response);
}
};
})(callback);
appAPI.message.toBackground(message, {channel: "message_to_background"});
break;
}
};
background.js:
appAPI.message.addListener({channel: "message_to_background"}, function(params) {
MsgHandler.handle(params.request, undefined, function(responseParams) {
appAPI.message.toActiveTab({'message_id': params.message_id, 'response': responseParams}, {channel: "message_from_background"});
});
});
msgHandler.js:
this.handle = function(request, sender, callback_out) {
function callback(response) {
if (typeof(callback_out) === 'function') {
callback_out(response);
}
}
switch (request.command) {
case "get":
switch (request.type) {
case "all":
var data = Controller.getData();
alert("[MsgHandler::handle] get / all, data.length = " + JSON.stringify(data).length + ", data = " + JSON.stringify(data)); // This happens in any computer.
callback({data: data});
break;
}
break;
}
return true; //this return is needed for chrome in order to execute callbacks
};
Sys.platform is always equal to 'crossrider'.
Update: When JSON.stringify(data).length was 5981 bytes the message was received, but when it was 10157 bytes the message was not received by the active tab (with appAPI.message.toActiveTab). What is the limit on the size of objects sent from the background and how do we send big objects to the tabs (up to 100KB)?
Our Extension ID is 43889. I'm using Internet Explorer 11 but this extension should work on all versions of Internet Explorer.
By the way, other calls from the background work, only this specific call doesn't work. We tried several times in Tom's computer and it never works.
Edit: I created a simple extension with the same problem, Extension ID is 67708. Here is the code of the simple extension:
extension.js:
appAPI.ready(function($) {
alert("appAPI.platform = " + appAPI.platform);
if (appAPI.platform === 'IE') {
appAPI.message.addListener({channel: "message_from_background"}, function(message) {
alert("message_from_background received, message_id = " + message.message_id + ", message.length = " + JSON.stringify(message).length + ", message = " + JSON.stringify(message));
});
appAPI.message.toBackground({}, {channel: "init_background"});
}
});
background.js:
appAPI.ready(function($) {
alert("appAPI.platform = " + appAPI.platform);
if (appAPI.platform === 'IE') {
var ready = false;
appAPI.message.addListener({channel: "init_background"}, function(params) {
if (ready === false) {
alert('init_background, ready = ' + ready);
ready = true;
var message_id = 9999;
var responseParams = {'a': 1, 'b': 2, 'c': 3};
alert('sending message to active tab, message_id = ' + message_id + ', responseParams.length = ' + JSON.stringify(responseParams).length);
appAPI.message.toActiveTab({'message_id': message_id, 'response': responseParams}, {channel: "message_from_background"});
var message_id = 9998;
var responseParams = {
// a big object
};
alert('sending message to active tab, message_id = ' + message_id + ', responseParams.length = ' + JSON.stringify(responseParams).length);
appAPI.message.toActiveTab({'message_id': message_id, 'response': responseParams}, {channel: "message_from_background"});
alert(appAPI.platform);
}
});
}
});
When JSON.stringify(responseParams).length is 19 bytes, the message is received by the active tab, but when it's 10576 bytes, the message is not received.
#Uri Thanks for the updated question.
In light of the new information, I would draw your attention to the note in the docs (appAP.message) about Internet Explorer limitations:
Messages are converted to JSON strings before they are sent. Due to a
limitation in Internet Explorer, the maximum length of the JSON string
is 8000 bytes (8Kb).
You can work around the issue by saving the data in the local database and sending a short message to the active tab to trigger it to read the data. The following is a simplified example of the flow:
background.js:
appAPI.ready(function($) {
appAPI.db.async.set(
'my-data',
myData,
appAPI.time.minutesFromNow(1),
function() {
appAPI.message.toActiveTab({type: 'get-data'});
}
);
});
extension.js:
appAPI.ready(function($) {
appAPI.message.addListener(function(msg) {
if (msg.type === 'get-data') {
appAPI.db.async.get('my-data', function(data) {
// do something with data
});
}
});
});
[Disclosure: I am a Crossrider employee]
OK, since the size of objects in the messages is limited to 8000 bytes, I divided the objects to packets of size up to 5000 bytes. Here is the code of my extension:
utils.js:
this.sendRequest = function(request, callback) {
if (typeof(callback) !== 'function') {
callback = function(response) {};
}
switch (Sys.platform) {
case 'crossrider':
var message = {request: request, message_id: Math.floor((Math.random() * 900000000000000) + 100000000000000)};
if (typeof thisObj.mCallbackMap === 'undefined') {
thisObj.mCallbackMap = {};
thisObj.mResponseObject = {};
appAPI.message.addListener({channel: "message_from_background"}, function(message) {
alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", checking message...");
if ((typeof(message) === 'object') && (!(message === null)) && (typeof(message['divided_object_length']) === 'number')) {
if (typeof thisObj.mResponseObject[message.message_id] === 'undefined') {
thisObj.mResponseObject[message.message_id] = {}
}
var limit = message['divided_object_length'];
var packet_id = message['packet_id'];
var packet = message['packet'];
alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", limit = " + limit + ", packet_id = " + packet_id + "...");
thisObj.mResponseObject[message.message_id]['packet_' + packet_id] = packet;
var message_is_ready = true;
for (var packet_id = 0; packet_id < limit; packet_id++) {
if (typeof thisObj.mResponseObject[message.message_id]['packet_' + packet_id] === 'undefined') {
var message_is_ready = false;
}
}
if (message_is_ready) {
delete message['divided_object_length'];
delete message['packet_id'];
delete message['packet'];
var s = '';
for (var packet_id = 0; packet_id < limit; packet_id++) {
s += thisObj.mResponseObject[message.message_id]['packet_' + packet_id];
}
message.response = JSON.parse(s);
delete thisObj.mResponseObject[message.message_id];
}
} else {
var message_is_ready = true;
}
alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", message_is_ready = " + message_is_ready + "...");
if (message_is_ready) {
if (typeof thisObj.mCallbackMap[message.message_id] === 'function') {
alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", calling function...");
thisObj.mCallbackMap[message.message_id](message.response);
delete thisObj.mCallbackMap[message.message_id];
}
}
});
}
(function(callback_inner) {
thisObj.mCallbackMap[message.message_id] = function(response) {
alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", checking inner function...");
if (typeof(callback_inner) === 'function') {
alert("[Utils::sendRequest] got response, message_id = " + message.message_id + ", calling inner function...");
callback_inner(response);
}
};
})(callback);
appAPI.message.toBackground(message, {channel: "message_to_background"});
break;
}
};
background.js:
appAPI.message.addListener({channel: "message_to_background"}, function(params) {
alert("background.js :: message received, params = " + JSON.stringify(params));
MsgHandler.handle(params.request, undefined, function(responseParams) {
alert("background.js :: message received callback, message_id = " + params.message_id + ", sending response.");
var s = JSON.stringify(responseParams);
if ((typeof(s) === "string") && (s.length > 5000)) {
var limit = Math.floor((s.length - 1) / 5000) + 1;
alert("background.js :: message received callback, message_id = " + params.message_id + ", sending response, s.length = " + s.length + ", limit = " + limit + ".");
for (var packet_id = 0; packet_id < limit; packet_id++) {
var message = {};
message['divided_object_length'] = limit;
message['message_id'] = params.message_id;
message['packet_id'] = packet_id;
message['packet'] = s.substr(packet_id * 5000, 5000);
appAPI.message.toActiveTab(message, {channel: "message_from_background"});
}
} else {
appAPI.message.toActiveTab({'message_id': params.message_id, 'response': responseParams}, {channel: "message_from_background"});
}
});
});
The rest of the code is the same like in my question (the alerts are just for debugging, we remove them in production).