diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c2e871d..91709175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # CHANGELOG -## X.X.X (comming soon) +## 4.9.0 (23 December 2021) Bugfixes: - When listening to messages directly, responses that where send directly after `addEventListener()` where missing because of inaccurate JavaScript timing. diff --git a/dist/es5node/broadcast-channel.js b/dist/es5node/broadcast-channel.js index 7b0114f1..8e6cefcd 100644 --- a/dist/es5node/broadcast-channel.js +++ b/dist/es5node/broadcast-channel.js @@ -260,9 +260,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/dist/esbrowser/broadcast-channel.js b/dist/esbrowser/broadcast-channel.js index 02e5f09b..fbc73866 100644 --- a/dist/esbrowser/broadcast-channel.js +++ b/dist/esbrowser/broadcast-channel.js @@ -242,9 +242,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/dist/esnode/broadcast-channel.js b/dist/esnode/broadcast-channel.js index 02e5f09b..fbc73866 100644 --- a/dist/esnode/broadcast-channel.js +++ b/dist/esnode/broadcast-channel.js @@ -242,9 +242,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/dist/lib/broadcast-channel.js b/dist/lib/broadcast-channel.js index 7b0114f1..8e6cefcd 100644 --- a/dist/lib/broadcast-channel.js +++ b/dist/lib/broadcast-channel.js @@ -260,9 +260,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/dist/lib/browser.js b/dist/lib/browser.js index f2586943..040216dc 100644 --- a/dist/lib/browser.js +++ b/dist/lib/browser.js @@ -261,9 +261,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/dist/lib/browser.min.js b/dist/lib/browser.min.js index 4f9e70dd..2a38b58d 100644 --- a/dist/lib/browser.min.js +++ b/dist/lib/browser.min.js @@ -1 +1 @@ -!function r(o,i,s){function a(t,e){if(!i[t]){if(!o[t]){var n="function"==typeof require&&require;if(!e&&n)return n(t,!0);if(u)return u(t,!0);throw(n=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",n}n=i[t]={exports:{}},o[t][0].call(n.exports,function(e){return a(o[t][1][e]||e)},n,n.exports,r,o,i,s)}return i[t].exports}for(var u="function"==typeof require&&require,e=0;e=e.time&&e.fn(t.data)})},n=e.method.microSeconds(),e._prepP?e._prepP.then(function(){e._iL=!0,e.method.onMessage(e._state,t,n)}):(e._iL=!0,e.method.onMessage(e._state,t,n)))}}(e)}function h(e,t,n){e._addEL[t]=e._addEL[t].filter(function(e){return e!==n}),function(e){{var t;e._iL&&!d(e)&&(e._iL=!1,t=e.method.microSeconds(),e.method.onMessage(e._state,null,t))}}(e)}(n.BroadcastChannel=a)._pubkey=!0,a.prototype={postMessage:function(e){if(this.closed)throw new Error("BroadcastChannel.postMessage(): Cannot post message after channel has closed");return l(this,"message",e)},postInternal:function(e){return l(this,"internal",e)},set onmessage(e){var t={time:this.method.microSeconds(),fn:e};h(this,"message",this._onML),e&&"function"==typeof e?(this._onML=t,f(this,"message",t)):this._onML=null},addEventListener:function(e,t){var n=this.method.microSeconds();f(this,e,{time:n,fn:t})},removeEventListener:function(e,t){var n=this._addEL[e].find(function(e){return e.fn===t});h(this,e,n)},close:function(){var e=this;if(!this.closed){s.delete(this),this.closed=!0;var t=this._prepP||o.PROMISE_RESOLVED_VOID;return this._onML=null,this._addEL.message=[],t.then(function(){return Promise.all(Array.from(e._uMP))}).then(function(){return Promise.all(e._befC.map(function(e){return e()}))}).then(function(){return e.method.close(e._state)})}},get type(){return this.method.type},get isClosed(){return this.closed}}},{"./method-chooser.js":6,"./options.js":11,"./util.js":12}],2:[function(e,t,n){"use strict";var r=e("./index.es5.js"),e=r.BroadcastChannel,r=r.createLeaderElection;window.BroadcastChannel2=e,window.createLeaderElection=r},{"./index.es5.js":3}],3:[function(e,t,n){"use strict";e=e("./index.js");t.exports={BroadcastChannel:e.BroadcastChannel,createLeaderElection:e.createLeaderElection,clearNodeFolder:e.clearNodeFolder,enforceOptions:e.enforceOptions,beLeader:e.beLeader}},{"./index.js":4}],4:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"BroadcastChannel",{enumerable:!0,get:function(){return r.BroadcastChannel}}),Object.defineProperty(n,"OPEN_BROADCAST_CHANNELS",{enumerable:!0,get:function(){return r.OPEN_BROADCAST_CHANNELS}}),Object.defineProperty(n,"beLeader",{enumerable:!0,get:function(){return o.beLeader}}),Object.defineProperty(n,"clearNodeFolder",{enumerable:!0,get:function(){return r.clearNodeFolder}}),Object.defineProperty(n,"createLeaderElection",{enumerable:!0,get:function(){return o.createLeaderElection}}),Object.defineProperty(n,"enforceOptions",{enumerable:!0,get:function(){return r.enforceOptions}});var r=e("./broadcast-channel"),o=e("./leader-election")},{"./broadcast-channel":1,"./leader-election":5}],5:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.beLeader=l,n.createLeaderElection=function(e,t){if(e._leaderElector)throw new Error("BroadcastChannel already has a leader-elector");t=function(e,t){e=e||{};(e=JSON.parse(JSON.stringify(e))).fallbackInterval||(e.fallbackInterval=3e3);e.responseTime||(e.responseTime=t.method.averageResponseTime(t.options));return e}(t,e);var n=new o(e,t);return e._befC.push(function(){return n.die()}),e._leaderElector=n};var u=e("./util.js"),r=e("unload"),o=function(e,t){var n=this;this.broadcastChannel=e,this._options=t,this.isLeader=!1,this.hasLeader=!1,this.isDead=!1,this.token=(0,u.randomToken)(),this._aplQ=u.PROMISE_RESOLVED_VOID,this._aplQC=0,this._unl=[],this._lstns=[],this._dpL=function(){},this._dpLC=!1;function r(e){"leader"===e.context&&("death"===e.action&&(n.hasLeader=!1),"tell"===e.action&&(n.hasLeader=!0))}this.broadcastChannel.addEventListener("internal",r),this._lstns.push(r)};function c(e,t){t={context:"leader",action:t,token:e.token};return e.broadcastChannel.postInternal(t)}function l(t){t.isLeader=!0,t.hasLeader=!0;var e=(0,r.add)(function(){return t.die()});t._unl.push(e);function n(e){"leader"===e.context&&"apply"===e.action&&c(t,"tell"),"leader"!==e.context||"tell"!==e.action||t._dpLC||(t._dpLC=!0,t._dpL(),c(t,"tell"))}return t.broadcastChannel.addEventListener("internal",n),t._lstns.push(n),c(t,"tell")}o.prototype={applyOnce:function(s){var a=this;if(this.isLeader)return(0,u.sleep)(0,!0);if(this.isDead)return(0,u.sleep)(0,!1);if(1a.token&&t(),"tell"===e.action&&(t(),a.hasLeader=!0))}var t,n=!1,r=new Promise(function(e){t=function(){n=!0,e()}}),o=[];a.broadcastChannel.addEventListener("internal",e);var i=s?4*a._options.responseTime:a._options.responseTime;return c(a,"apply").then(function(){return Promise.race([(0,u.sleep)(i),r.then(function(){return Promise.reject(new Error)})])}).then(function(){return c(a,"apply")}).then(function(){return Promise.race([(0,u.sleep)(i),r.then(function(){return Promise.reject(new Error)})])}).catch(function(){}).then(function(){return a.broadcastChannel.removeEventListener("internal",e),!n&&l(a).then(function(){return!0})})}return this._aplQC=this._aplQC+1,this._aplQ=this._aplQ.then(e).then(function(){a._aplQC=a._aplQC-1}),this._aplQ.then(function(){return a.isLeader})},awaitLeadership:function(){return this._aLP||(this._aLP=function(o){if(o.isLeader)return u.PROMISE_RESOLVED_VOID;return new Promise(function(e){var t=!1;function n(){t||(t=!0,o.broadcastChannel.removeEventListener("internal",r),e(!0))}o.applyOnce().then(function(){o.isLeader&&n()}),function e(){return(0,u.sleep)(o._options.fallbackInterval).then(function(){if(!o.isDead&&!t)return o.isLeader?void n():o.applyOnce(!0).then(function(){(o.isLeader?n:e)()})})}();var r=function(e){"leader"===e.context&&"death"===e.action&&(o.hasLeader=!1,o.applyOnce().then(function(){o.isLeader&&n()}))};o.broadcastChannel.addEventListener("internal",r),o._lstns.push(r)})}(this)),this._aLP},set onduplicate(e){this._dpL=e},die:function(){var t=this;return this._lstns.forEach(function(e){return t.broadcastChannel.removeEventListener("internal",e)}),this._lstns=[],this._unl.forEach(function(e){return e.remove()}),this._unl=[],this.isLeader&&(this.hasLeader=!1,this.isLeader=!1),this.isDead=!0,c(this,"death")}}},{"./util.js":12,unload:20}],6:[function(e,t,n){"use strict";var r=e("@babel/runtime/helpers/interopRequireDefault");e("@babel/runtime/helpers/typeof");Object.defineProperty(n,"__esModule",{value:!0}),n.chooseMethod=function(t){var e=[].concat(t.methods,u).filter(Boolean);if(t.type){if("simulate"===t.type)return s.default;var n=e.find(function(e){return e.type===t.type});if(n)return n;throw new Error("method-type "+t.type+" not found")}t.webWorkerSupport||a.isNode||(e=e.filter(function(e){return"idb"!==e.type}));e=e.find(function(e){return e.canBeUsed()});{if(e)return e;throw new Error("No useable method found in "+JSON.stringify(u.map(function(e){return e.type})))}};var o=r(e("./methods/native.js")),i=r(e("./methods/indexed-db.js")),n=r(e("./methods/localstorage.js")),s=r(e("./methods/simulate.js")),a=e("./util");var u=[o.default,i.default,n.default]},{"./methods/indexed-db.js":7,"./methods/localstorage.js":8,"./methods/native.js":9,"./methods/simulate.js":10,"./util":12,"@babel/runtime/helpers/interopRequireDefault":13,"@babel/runtime/helpers/typeof":14}],7:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.averageResponseTime=y,n.canBeUsed=w,n.cleanOldMessages=p,n.close=b,n.create=m,n.createDatabase=c,n.default=void 0,n.getAllMessages=function(e){var n=e.transaction(a).objectStore(a),r=[];return new Promise(function(t){n.openCursor().onsuccess=function(e){e=e.target.result;e?(r.push(e.value),e.continue()):t(r)}})},n.getIdb=u,n.getMessagesHigherThan=d,n.getOldMessages=h,n.microSeconds=void 0,n.onMessage=g,n.postMessage=_,n.removeMessageById=f,n.type=void 0,n.writeMessage=l;var o=e("../util.js"),i=e("oblivious-set"),s=e("../options"),e=o.microSeconds;n.microSeconds=e;var r="pubkey.broadcast-channel-0-",a="messages";function u(){if("undefined"!=typeof indexedDB)return indexedDB;if("undefined"!=typeof window){if(void 0!==window.mozIndexedDB)return window.mozIndexedDB;if(void 0!==window.webkitIndexedDB)return window.webkitIndexedDB;if(void 0!==window.msIndexedDB)return window.msIndexedDB}return!1}function c(e){var n=u().open(r+e,1);return n.onupgradeneeded=function(e){e.target.result.createObjectStore(a,{keyPath:"id",autoIncrement:!0})},new Promise(function(e,t){n.onerror=function(e){return t(e)},n.onsuccess=function(){e(n.result)}})}function l(e,t,n){var r={uuid:t,time:(new Date).getTime(),data:n},o=e.transaction([a],"readwrite");return new Promise(function(e,t){o.oncomplete=function(){return e()},o.onerror=function(e){return t(e)},o.objectStore(a).add(r)})}function d(e,n){var r=e.transaction(a).objectStore(a),o=[];return new Promise(function(t){(function(){try{var e=IDBKeyRange.bound(n+1,1/0);return r.openCursor(e)}catch(e){return r.openCursor()}})().onsuccess=function(e){e=e.target.result;e?e.value.idn.lastCursorId&&(n.lastCursorId=e.id),e}).filter(function(e){return t=n,(e=e).uuid!==t.uuid&&(!t.eMIs.has(e.id)&&!(e.data.time=t&&e.fn(n.data)})},n=e.method.microSeconds(),e._prepP?e._prepP.then(function(){e._iL=!0,e.method.onMessage(e._state,t,n)}):(e._iL=!0,e.method.onMessage(e._state,t,n)))}}(e)}function h(e,t,n){e._addEL[t]=e._addEL[t].filter(function(e){return e!==n}),function(e){{var t;e._iL&&!d(e)&&(e._iL=!1,t=e.method.microSeconds(),e.method.onMessage(e._state,null,t))}}(e)}(n.BroadcastChannel=a)._pubkey=!0,a.prototype={postMessage:function(e){if(this.closed)throw new Error("BroadcastChannel.postMessage(): Cannot post message after channel has closed");return l(this,"message",e)},postInternal:function(e){return l(this,"internal",e)},set onmessage(e){var t={time:this.method.microSeconds(),fn:e};h(this,"message",this._onML),e&&"function"==typeof e?(this._onML=t,f(this,"message",t)):this._onML=null},addEventListener:function(e,t){var n=this.method.microSeconds();f(this,e,{time:n,fn:t})},removeEventListener:function(e,t){var n=this._addEL[e].find(function(e){return e.fn===t});h(this,e,n)},close:function(){var e=this;if(!this.closed){s.delete(this),this.closed=!0;var t=this._prepP||o.PROMISE_RESOLVED_VOID;return this._onML=null,this._addEL.message=[],t.then(function(){return Promise.all(Array.from(e._uMP))}).then(function(){return Promise.all(e._befC.map(function(e){return e()}))}).then(function(){return e.method.close(e._state)})}},get type(){return this.method.type},get isClosed(){return this.closed}}},{"./method-chooser.js":6,"./options.js":11,"./util.js":12}],2:[function(e,t,n){"use strict";var r=e("./index.es5.js"),e=r.BroadcastChannel,r=r.createLeaderElection;window.BroadcastChannel2=e,window.createLeaderElection=r},{"./index.es5.js":3}],3:[function(e,t,n){"use strict";e=e("./index.js");t.exports={BroadcastChannel:e.BroadcastChannel,createLeaderElection:e.createLeaderElection,clearNodeFolder:e.clearNodeFolder,enforceOptions:e.enforceOptions,beLeader:e.beLeader}},{"./index.js":4}],4:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"BroadcastChannel",{enumerable:!0,get:function(){return r.BroadcastChannel}}),Object.defineProperty(n,"OPEN_BROADCAST_CHANNELS",{enumerable:!0,get:function(){return r.OPEN_BROADCAST_CHANNELS}}),Object.defineProperty(n,"beLeader",{enumerable:!0,get:function(){return o.beLeader}}),Object.defineProperty(n,"clearNodeFolder",{enumerable:!0,get:function(){return r.clearNodeFolder}}),Object.defineProperty(n,"createLeaderElection",{enumerable:!0,get:function(){return o.createLeaderElection}}),Object.defineProperty(n,"enforceOptions",{enumerable:!0,get:function(){return r.enforceOptions}});var r=e("./broadcast-channel"),o=e("./leader-election")},{"./broadcast-channel":1,"./leader-election":5}],5:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.beLeader=l,n.createLeaderElection=function(e,t){if(e._leaderElector)throw new Error("BroadcastChannel already has a leader-elector");t=function(e,t){e=e||{};(e=JSON.parse(JSON.stringify(e))).fallbackInterval||(e.fallbackInterval=3e3);e.responseTime||(e.responseTime=t.method.averageResponseTime(t.options));return e}(t,e);var n=new o(e,t);return e._befC.push(function(){return n.die()}),e._leaderElector=n};var u=e("./util.js"),r=e("unload"),o=function(e,t){var n=this;this.broadcastChannel=e,this._options=t,this.isLeader=!1,this.hasLeader=!1,this.isDead=!1,this.token=(0,u.randomToken)(),this._aplQ=u.PROMISE_RESOLVED_VOID,this._aplQC=0,this._unl=[],this._lstns=[],this._dpL=function(){},this._dpLC=!1;function r(e){"leader"===e.context&&("death"===e.action&&(n.hasLeader=!1),"tell"===e.action&&(n.hasLeader=!0))}this.broadcastChannel.addEventListener("internal",r),this._lstns.push(r)};function c(e,t){t={context:"leader",action:t,token:e.token};return e.broadcastChannel.postInternal(t)}function l(t){t.isLeader=!0,t.hasLeader=!0;var e=(0,r.add)(function(){return t.die()});t._unl.push(e);function n(e){"leader"===e.context&&"apply"===e.action&&c(t,"tell"),"leader"!==e.context||"tell"!==e.action||t._dpLC||(t._dpLC=!0,t._dpL(),c(t,"tell"))}return t.broadcastChannel.addEventListener("internal",n),t._lstns.push(n),c(t,"tell")}o.prototype={applyOnce:function(s){var a=this;if(this.isLeader)return(0,u.sleep)(0,!0);if(this.isDead)return(0,u.sleep)(0,!1);if(1a.token&&t(),"tell"===e.action&&(t(),a.hasLeader=!0))}var t,n=!1,r=new Promise(function(e){t=function(){n=!0,e()}}),o=[];a.broadcastChannel.addEventListener("internal",e);var i=s?4*a._options.responseTime:a._options.responseTime;return c(a,"apply").then(function(){return Promise.race([(0,u.sleep)(i),r.then(function(){return Promise.reject(new Error)})])}).then(function(){return c(a,"apply")}).then(function(){return Promise.race([(0,u.sleep)(i),r.then(function(){return Promise.reject(new Error)})])}).catch(function(){}).then(function(){return a.broadcastChannel.removeEventListener("internal",e),!n&&l(a).then(function(){return!0})})}return this._aplQC=this._aplQC+1,this._aplQ=this._aplQ.then(e).then(function(){a._aplQC=a._aplQC-1}),this._aplQ.then(function(){return a.isLeader})},awaitLeadership:function(){return this._aLP||(this._aLP=function(o){if(o.isLeader)return u.PROMISE_RESOLVED_VOID;return new Promise(function(e){var t=!1;function n(){t||(t=!0,o.broadcastChannel.removeEventListener("internal",r),e(!0))}o.applyOnce().then(function(){o.isLeader&&n()}),function e(){return(0,u.sleep)(o._options.fallbackInterval).then(function(){if(!o.isDead&&!t)return o.isLeader?void n():o.applyOnce(!0).then(function(){(o.isLeader?n:e)()})})}();var r=function(e){"leader"===e.context&&"death"===e.action&&(o.hasLeader=!1,o.applyOnce().then(function(){o.isLeader&&n()}))};o.broadcastChannel.addEventListener("internal",r),o._lstns.push(r)})}(this)),this._aLP},set onduplicate(e){this._dpL=e},die:function(){var t=this;return this._lstns.forEach(function(e){return t.broadcastChannel.removeEventListener("internal",e)}),this._lstns=[],this._unl.forEach(function(e){return e.remove()}),this._unl=[],this.isLeader&&(this.hasLeader=!1,this.isLeader=!1),this.isDead=!0,c(this,"death")}}},{"./util.js":12,unload:20}],6:[function(e,t,n){"use strict";var r=e("@babel/runtime/helpers/interopRequireDefault");e("@babel/runtime/helpers/typeof");Object.defineProperty(n,"__esModule",{value:!0}),n.chooseMethod=function(t){var e=[].concat(t.methods,u).filter(Boolean);if(t.type){if("simulate"===t.type)return s.default;var n=e.find(function(e){return e.type===t.type});if(n)return n;throw new Error("method-type "+t.type+" not found")}t.webWorkerSupport||a.isNode||(e=e.filter(function(e){return"idb"!==e.type}));e=e.find(function(e){return e.canBeUsed()});{if(e)return e;throw new Error("No useable method found in "+JSON.stringify(u.map(function(e){return e.type})))}};var o=r(e("./methods/native.js")),i=r(e("./methods/indexed-db.js")),n=r(e("./methods/localstorage.js")),s=r(e("./methods/simulate.js")),a=e("./util");var u=[o.default,i.default,n.default]},{"./methods/indexed-db.js":7,"./methods/localstorage.js":8,"./methods/native.js":9,"./methods/simulate.js":10,"./util":12,"@babel/runtime/helpers/interopRequireDefault":13,"@babel/runtime/helpers/typeof":14}],7:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.averageResponseTime=y,n.canBeUsed=w,n.cleanOldMessages=p,n.close=b,n.create=m,n.createDatabase=c,n.default=void 0,n.getAllMessages=function(e){var n=e.transaction(a).objectStore(a),r=[];return new Promise(function(t){n.openCursor().onsuccess=function(e){e=e.target.result;e?(r.push(e.value),e.continue()):t(r)}})},n.getIdb=u,n.getMessagesHigherThan=d,n.getOldMessages=h,n.microSeconds=void 0,n.onMessage=g,n.postMessage=_,n.removeMessageById=f,n.type=void 0,n.writeMessage=l;var o=e("../util.js"),i=e("oblivious-set"),s=e("../options"),e=o.microSeconds;n.microSeconds=e;var r="pubkey.broadcast-channel-0-",a="messages";function u(){if("undefined"!=typeof indexedDB)return indexedDB;if("undefined"!=typeof window){if(void 0!==window.mozIndexedDB)return window.mozIndexedDB;if(void 0!==window.webkitIndexedDB)return window.webkitIndexedDB;if(void 0!==window.msIndexedDB)return window.msIndexedDB}return!1}function c(e){var n=u().open(r+e,1);return n.onupgradeneeded=function(e){e.target.result.createObjectStore(a,{keyPath:"id",autoIncrement:!0})},new Promise(function(e,t){n.onerror=function(e){return t(e)},n.onsuccess=function(){e(n.result)}})}function l(e,t,n){var r={uuid:t,time:(new Date).getTime(),data:n},o=e.transaction([a],"readwrite");return new Promise(function(e,t){o.oncomplete=function(){return e()},o.onerror=function(e){return t(e)},o.objectStore(a).add(r)})}function d(e,n){var r=e.transaction(a).objectStore(a),o=[];return new Promise(function(t){(function(){try{var e=IDBKeyRange.bound(n+1,1/0);return r.openCursor(e)}catch(e){return r.openCursor()}})().onsuccess=function(e){e=e.target.result;e?e.value.idn.lastCursorId&&(n.lastCursorId=e.id),e}).filter(function(e){return t=n,(e=e).uuid!==t.uuid&&(!t.eMIs.has(e.id)&&!(e.data.time= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; @@ -12374,7 +12386,6 @@ function run() { rand = new Date().getTime(); channel.onmessage = function (msg) { - console.log('main: recieved msg' + JSON.stringify(msg)); answerPool[msg.from] = msg; var textnode = document.createTextNode(JSON.stringify(msg) + '
'); msgContainer.appendChild(textnode); @@ -12670,7 +12681,9 @@ function run() { return true; })]).then(function (errored) { if (errored) { - throw new Error('timed out for msgId ' + msgId); + var errorMessage = 'ERROR startWorkerTest() timed out for msgId ' + msgId; + console.error(errorMessage); + throw new Error(errorMessage); } }); diff --git a/docs/iframe.js b/docs/iframe.js index e5d96778..a99b8abd 100644 --- a/docs/iframe.js +++ b/docs/iframe.js @@ -261,9 +261,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/docs/index.js b/docs/index.js index 2950ad8e..d109a2aa 100644 --- a/docs/index.js +++ b/docs/index.js @@ -261,9 +261,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/docs/leader-iframe.js b/docs/leader-iframe.js index f4d30aff..eb9df551 100644 --- a/docs/leader-iframe.js +++ b/docs/leader-iframe.js @@ -261,9 +261,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/docs/worker.js b/docs/worker.js index b43ad892..6fef9299 100644 --- a/docs/worker.js +++ b/docs/worker.js @@ -261,9 +261,21 @@ function _startListening(channel) { if (!channel._iL && _hasMessageListeners(channel)) { // someone is listening, start subscribing var listenerFn = function listenerFn(msgObj) { - channel._addEL[msgObj.type].forEach(function (obj) { - if (msgObj.time >= obj.time) { - obj.fn(msgObj.data); + channel._addEL[msgObj.type].forEach(function (listenerObject) { + /** + * Getting the current time in JavaScript has no good precision. + * So instead of only listening to events that happend 'after' the listener + * was added, we also listen to events that happended 100ms before it. + * This ensures that when another process, like a WebWorker, sends events + * we do not miss them out because their timestamp is a bit off compared to the main process. + * Not doing this would make messages missing when we send data directly after subscribing and awaiting a response. + * @link https://johnresig.com/blog/accuracy-of-javascript-time/ + */ + var hundredMsInMicro = 100 * 1000; + var minMessageTime = listenerObject.time - hundredMsInMicro; + + if (msgObj.time >= minMessageTime) { + listenerObject.fn(msgObj.data); } }); }; diff --git a/test/scripts/e2e.js b/test/scripts/e2e.js index 6e2ff3f1..5a2095db 100644 --- a/test/scripts/e2e.js +++ b/test/scripts/e2e.js @@ -79,8 +79,6 @@ function run() { const rand = new Date().getTime(); channel.onmessage = function (msg) { - console.log('main: recieved msg' + JSON.stringify(msg)); - answerPool[msg.from] = msg; var textnode = document.createTextNode(JSON.stringify(msg) + '
'); msgContainer.appendChild(textnode);