aboutsummaryrefslogtreecommitdiffstats
path: root/lib/CallbackWrapper.jsm
blob: 8c077329540413537893e13ec7fc06fc643459c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*******************************************************************************

    η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);
};