|
| 1 | +/* |
| 2 | + * decaffeinate suggestions: |
| 3 | + * DS101: Remove unnecessary use of Array.from |
| 4 | + * DS102: Remove unnecessary code created because of implicit returns |
| 5 | + * DS202: Simplify dynamic range loops |
| 6 | + * DS205: Consider reworking code to avoid use of IIFEs |
| 7 | + * DS207: Consider shorter variations of null checks |
| 8 | + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md |
| 9 | + */ |
| 10 | +import Bacon from "../dist/Bacon"; |
| 11 | +const toKb = x => (x / 1024).toFixed(2) + ' KiB'; |
| 12 | +const toMb = x => (x / 1024 / 1024).toFixed(2) + ' MiB'; |
| 13 | + |
| 14 | +const byteFormat = function(bytes, comparison) { |
| 15 | + if (Math.abs(comparison || bytes) > (512 * 1024)) { |
| 16 | + return toMb(bytes); |
| 17 | + } else { |
| 18 | + return toKb(bytes); |
| 19 | + } |
| 20 | +}; |
| 21 | + |
| 22 | +const lpad = function(string, length) { |
| 23 | + if (length == null) { length = 12; } |
| 24 | + while(string.length < length) { |
| 25 | + string = ` ${string}`; |
| 26 | + } |
| 27 | + return string; |
| 28 | +}; |
| 29 | + |
| 30 | +const rpad = function(string, length) { |
| 31 | + if (length == null) { length = 12; } |
| 32 | + while(string.length < length) { |
| 33 | + string = `${string} `; |
| 34 | + } |
| 35 | + return string; |
| 36 | +}; |
| 37 | +const measure = function(fun) { |
| 38 | + global.gc(); |
| 39 | + const lastMemoryUsage = process.memoryUsage().heapUsed; |
| 40 | + const startTime = Date.now(); |
| 41 | + fun(); |
| 42 | + const duration = Date.now() - startTime; |
| 43 | + global.gc(); |
| 44 | + return [process.memoryUsage().heapUsed - lastMemoryUsage, duration]; |
| 45 | +}; |
| 46 | + |
| 47 | +const sum = xs => xs.reduce((sum, x) => sum + x); |
| 48 | +const mean = xs => sum(xs) / xs.length; |
| 49 | +const stddev = function(xs) { |
| 50 | + const avg = mean(xs); |
| 51 | + return Math.pow(mean(Array.from(xs).map((x) => Math.pow((x - avg), 2))), 0.5); |
| 52 | +}; |
| 53 | + |
| 54 | +const processResults = function(results, i) { |
| 55 | + const values = (Array.from(results).map((x) => x[i])); |
| 56 | + |
| 57 | + return { |
| 58 | + mean: mean(values.slice(2)), |
| 59 | + stddev: stddev(values.slice(2)) |
| 60 | + }; |
| 61 | +}; |
| 62 | + |
| 63 | +const printResult = function(label, result, forcePrefix) { |
| 64 | + if (forcePrefix == null) { forcePrefix = false; } |
| 65 | + var prefix = prefix && (result.mean > 0) ? '+' : ''; |
| 66 | + return console.log(` ${rpad(label, 20)}`, lpad(prefix + byteFormat(result.mean), 12), '\u00b1', byteFormat(result.stddev, result.mean)); |
| 67 | +}; |
| 68 | +const createNObservable = function(count, generator) { |
| 69 | + let withoutSubscriber, withSubscriber, afterCleanup, reSubscribe, afterReCleanup; |
| 70 | + const n = Math.floor(count / 10); |
| 71 | + const m = 10; |
| 72 | + |
| 73 | + const results = (() => { |
| 74 | + const result = []; |
| 75 | + for (var j = 0, i = j, end = m, asc = 0 <= end; asc ? j < end : j > end; asc ? j++ : j--, i = j) { |
| 76 | + global.gc(); |
| 77 | + var objects = new Array(n); // Preallocate array of n elements |
| 78 | + var unsubscribers = new Array(n); |
| 79 | + const subscribe = () => |
| 80 | + (() => { |
| 81 | + let asc1, end1; |
| 82 | + const result1 = []; |
| 83 | + for (i = 0, end1 = objects.length, asc1 = 0 <= end1; asc1 ? i < end1 : i > end1; asc1 ? i++ : i--) { |
| 84 | + result1.push(unsubscribers[i] = objects[i].onValue(noop)); |
| 85 | + } |
| 86 | + return result1; |
| 87 | + })() |
| 88 | + ; |
| 89 | + const unsubscribe = () => |
| 90 | + (() => { |
| 91 | + let asc1, end1; |
| 92 | + const result1 = []; |
| 93 | + for (i = 0, end1 = objects.length, asc1 = 0 <= end1; asc1 ? i < end1 : i > end1; asc1 ? i++ : i--) { |
| 94 | + unsubscribers[i](); |
| 95 | + result1.push(unsubscribers[i] = null); |
| 96 | + } |
| 97 | + return result1; |
| 98 | + })() |
| 99 | + ; |
| 100 | + |
| 101 | + global.gc(); |
| 102 | + withoutSubscriber = measure(() => |
| 103 | + (() => { |
| 104 | + let asc1, end1; |
| 105 | + const result1 = []; |
| 106 | + for (i = 0, end1 = objects.length, asc1 = 0 <= end1; asc1 ? i < end1 : i > end1; asc1 ? i++ : i--) { |
| 107 | + result1.push(objects[i] = generator(i)); |
| 108 | + } |
| 109 | + return result1; |
| 110 | + })()); |
| 111 | + |
| 112 | + withSubscriber = measure(subscribe); |
| 113 | + afterCleanup = measure(unsubscribe); |
| 114 | + reSubscribe = measure(subscribe); |
| 115 | + afterReCleanup = measure(unsubscribe); |
| 116 | + |
| 117 | + objects = null; |
| 118 | + unsubscribers = null; |
| 119 | + result.push([withoutSubscriber[0]/n, withSubscriber[0]/n, afterCleanup[0]/n, reSubscribe[0]/n, afterReCleanup[0]/n]); |
| 120 | + } |
| 121 | + return result; |
| 122 | + })(); |
| 123 | + |
| 124 | + withoutSubscriber = processResults(results, 0); |
| 125 | + withSubscriber = processResults(results, 1); |
| 126 | + afterCleanup = processResults(results, 2); |
| 127 | + reSubscribe = processResults(results, 3); |
| 128 | + afterReCleanup = processResults(results, 4); |
| 129 | + |
| 130 | + printResult('w/o subscription', withoutSubscriber); |
| 131 | + printResult('with subscription', withSubscriber, true); |
| 132 | + printResult('unsubscribe', afterCleanup, true); |
| 133 | + printResult('subscribe again', reSubscribe, true); |
| 134 | + return printResult('unsubscribe again', afterReCleanup, true); |
| 135 | +}; |
| 136 | + |
| 137 | +const title = text => console.log(`\n${text}`); |
| 138 | +var noop = function() {}; |
| 139 | + |
| 140 | + |
| 141 | +// Keep reference to listeners during test run |
| 142 | +const fakeSource = { |
| 143 | + listeners: [], |
| 144 | + subscribe(listener) { return this.listeners.push(listener); }, |
| 145 | + unsubscribe(listener) { |
| 146 | + const index = this.listeners.indexOf(listener); |
| 147 | + if (index !== -1) { return this.listeners.splice(index, 1); } |
| 148 | + } |
| 149 | +}; |
| 150 | + |
| 151 | + |
| 152 | +const eventStream = () => |
| 153 | + new Bacon.EventStream(function(sink) { |
| 154 | + fakeSource.subscribe(sink); |
| 155 | + return () => fakeSource.unsubscribe(sink); |
| 156 | + }) |
| 157 | +; |
| 158 | + |
| 159 | + |
| 160 | +export default { createNObservable, eventStream, title, noop }; |
0 commit comments