diff --git a/IPython/html/static/services/kernels/kernel.js b/IPython/html/static/services/kernels/kernel.js
index f414507..42478ae 100644
--- a/IPython/html/static/services/kernels/kernel.js
+++ b/IPython/html/static/services/kernels/kernel.js
@@ -41,6 +41,7 @@ define([
this.username = "username";
this.session_id = utils.uuid();
this._msg_callbacks = {};
+ this._msg_queue = Promise.resolve();
this.info_reply = {}; // kernel_info_reply stored here after starting
if (typeof(WebSocket) !== 'undefined') {
@@ -854,7 +855,10 @@ define([
};
Kernel.prototype._handle_ws_message = function (e) {
- serialize.deserialize(e.data, $.proxy(this._finish_ws_message, this));
+ this._msg_queue = this._msg_queue.then(function() {
+ return serialize.deserialize(e.data);
+ }).then($.proxy(this._finish_ws_message, this))
+ .catch(utils.reject("Couldn't process kernel message", true));
};
Kernel.prototype._finish_ws_message = function (msg) {
diff --git a/IPython/html/static/services/kernels/serialize.js b/IPython/html/static/services/kernels/serialize.js
index 4da4c9a..9fb8d28 100644
--- a/IPython/html/static/services/kernels/serialize.js
+++ b/IPython/html/static/services/kernels/serialize.js
@@ -30,7 +30,7 @@ define([
return msg;
};
- var _deserialize_binary = function(data, callback) {
+ var _deserialize_binary = function(data) {
/**
* deserialize the binary message format
* callback will be called with a message whose buffers attribute
@@ -39,28 +39,31 @@ define([
if (data instanceof Blob) {
// data is Blob, have to deserialize from ArrayBuffer in reader callback
var reader = new FileReader();
- reader.onload = function () {
- var msg = _deserialize_array_buffer(this.result);
- callback(msg);
- };
+ var promise = new Promise(function(resolve, reject) {
+ reader.onload = function () {
+ var msg = _deserialize_array_buffer(this.result);
+ resolve(msg);
+ };
+ });
reader.readAsArrayBuffer(data);
+ return promise;
} else {
// data is ArrayBuffer, can deserialize directly
var msg = _deserialize_array_buffer(data);
- callback(msg);
+ return msg;
}
};
- var deserialize = function (data, callback) {
+ var deserialize = function (data) {
/**
- * deserialize a message and pass the unpacked message object to callback
+ * deserialize a message and return a promise for the unpacked message
*/
if (typeof data === "string") {
// text JSON message
- callback(JSON.parse(data));
+ return Promise.resolve(JSON.parse(data));
} else {
// binary message
- _deserialize_binary(data, callback);
+ return Promise.resolve(_deserialize_binary(data));
}
};
@@ -117,4 +120,4 @@ define([
serialize: serialize
};
return exports;
-});
\ No newline at end of file
+});
diff --git a/IPython/html/tests/services/serialize.js b/IPython/html/tests/services/serialize.js
index fe61bf1..e51edf5 100644
--- a/IPython/html/tests/services/serialize.js
+++ b/IPython/html/tests/services/serialize.js
@@ -51,7 +51,9 @@ casper.notebook_test(function () {
this.then(function () {
var index = this.append_cell([
"buffers = [b'\\xFF\\x00', b'\\x00\\x01\\x02']",
- "comm.send(data='hi', buffers=buffers)"
+ "comm.send(data='message 0', buffers=buffers)",
+ "comm.send(data='message 1')",
+ "comm.send(data='message 2', buffers=buffers)",
].join('\n'), 'code');
this.execute_cell(index);
});
@@ -59,7 +61,7 @@ casper.notebook_test(function () {
// wait for capture
this.waitFor(function () {
return this.evaluate(function () {
- return IPython._msgs.length > 0;
+ return IPython._msgs.length >= 3;
});
});
@@ -68,14 +70,22 @@ casper.notebook_test(function () {
var msgs = this.evaluate(function () {
return IPython._msgs;
});
- this.test.assertEquals(msgs.length, 1, "Captured comm message");
- var buffers = msgs[0].buffers;
- this.test.assertEquals(buffers.length, 2, "comm message has buffers");
+ this.test.assertEquals(msgs.length, 3, "Captured three comm messages");
+
+
+
+ // check the messages came in the right order
+ this.test.assertEquals(msgs[0].content.data, "message 0", "message 0 processed first");
+ this.test.assertEquals(msgs[0].buffers.length, 2, "comm message 0 has two buffers");
+ this.test.assertEquals(msgs[1].content.data, "message 1", "message 1 processed second");
+ this.test.assertEquals(msgs[1].buffers.length, 0, "comm message 1 has no buffers");
+ this.test.assertEquals(msgs[2].content.data, "message 2", "message 2 processed third");
+ this.test.assertEquals(msgs[2].buffers.length, 2, "comm message 2 has two buffers");
// extract attributes to test in evaluate,
// because the raw DataViews can't be passed across
- var buf_info = function (index) {
- var buf = IPython._msgs[0].buffers[index];
+ var buf_info = function (message, index) {
+ var buf = IPython._msgs[message].buffers[index];
var data = {};
data.byteLength = buf.byteLength;
data.bytes = [];
@@ -85,18 +95,22 @@ casper.notebook_test(function () {
return data;
};
- buf0 = this.evaluate(buf_info, 0);
- buf1 = this.evaluate(buf_info, 1);
- this.test.assertEquals(buf0.byteLength, 2, 'buf[0] has correct size');
- this.test.assertEquals(buf0.bytes, [255, 0], 'buf[0] has correct bytes');
- this.test.assertEquals(buf1.byteLength, 3, 'buf[1] has correct size');
- this.test.assertEquals(buf1.bytes, [0, 1, 2], 'buf[1] has correct bytes');
+ var msgs_with_buffers = [0, 2];
+ for (var i = 0; i < msgs_with_buffers.length; i++) {
+ msg_index = msgs_with_buffers[i];
+ buf0 = this.evaluate(buf_info, msg_index, 0);
+ buf1 = this.evaluate(buf_info, msg_index, 1);
+ this.test.assertEquals(buf0.byteLength, 2, 'buf[0] has correct size in message '+msg_index);
+ this.test.assertEquals(buf0.bytes, [255, 0], 'buf[0] has correct bytes in message '+msg_index);
+ this.test.assertEquals(buf1.byteLength, 3, 'buf[1] has correct size in message '+msg_index);
+ this.test.assertEquals(buf1.bytes, [0, 1, 2], 'buf[1] has correct bytes in message '+msg_index);
+ }
});
// validate captured buffers Python-side
this.then(function () {
var index = this.append_cell([
- "assert len(msgs) == 1, len(msgs)",
+ "assert len(msgs) == 3, len(msgs)",
"bufs = msgs[0]['buffers']",
"assert len(bufs) == len(buffers), bufs",
"assert bufs[0].bytes == buffers[0], bufs[0].bytes",
@@ -107,7 +121,7 @@ casper.notebook_test(function () {
this.wait_for_output(index);
this.then(function () {
var out = this.get_output_cell(index);
- this.test.assertEquals(out['text/plain'], '1', "Python received buffers");
+ this.test.assertEquals(out.data['text/plain'], '1', "Python received buffers");
});
});
});