/******************************************************************************* ηMatrix - a browser extension to black/white list requests. Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors Copyright (C) 2019-2020 Alessio Vanni This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. Home: https://libregit.spks.xyz/heckyel/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ 'use strict'; var EXPORTED_SYMBOLS = ['CallbackWrapper']; var junkyard = []; var CallbackWrapper = function (messageManager, channelName, listenerId, requestId) { // This allows to avoid creating a closure for every single // message which expects an answer. Having a closure created // each time a message is processed has been always bothering // me. Another benefit of the implementation here is to reuse // the callback proxy object, so less memory churning. // // https://developers.google.com/speed/articles/optimizing-javascript // "Creating a closure is significantly slower then creating // an inner function without a closure, and much slower than // reusing a static function" // // http://hacksoflife.blogspot.ca/2015/01/the-four-horsemen-of-performance.html // "the dreaded 'uniformly slow code' case where every // function takes 1% of CPU and you have to make one hundred // separate performance optimizations to improve performance // at all" // // http://jsperf.com/closure-no-closure/2 this.callback = this.proxy.bind(this); // bind once this.init(messageManager, channelName, listenerId, requestId); }; CallbackWrapper.factory = function (messageManager, channelName, listenerId, requestId) { let wrapper = junkyard.pop(); if (wrapper) { wrapper.init(messageManager, channelName, listenerId, requestId); return wrapper; } return new CallbackWrapper(messageManager, channelName, listenerId, requestId); }; CallbackWrapper.prototype.init = function (messageManager, channelName, listenerId, requestId) { this.messageManager = messageManager; this.channelName = channelName; this.listenerId = listenerId; this.requestId = requestId; }; CallbackWrapper.prototype.proxy = function (response) { let message = JSON.stringify({ requestId: this.requestId, channelName: this.channelName, msg: response !== undefined ? response : null }); if (this.messageManager.sendAsyncMessage) { this.messageManager.sendAsyncMessage(this.listenerId, message); } else { this.messageManager.broadcastAsyncMessage(this.listenerId, message); } // Mark for reuse this.messageManager = this.channelName = this.requestId = this.listenerId = null; junkyard.push(this); };