PageSourceSearch

https://gameinformer.com/modules/custom/gi_async_load/js/bus.js?v=1790718905

js gameinformer.com collected 2026-10-02 02:14:46 UTC 7,775 bytes, 258 lines download raw bytes

1'use strict';
2
3/**
4 * The script is designed to collect interdependent scripts
5 * that need to be executed in a specific order. Scripts in the queue are executed strictly one after another
6 * to avoid conflicts between them in case elements are added to the queue during queue processing.
7 * Queues are classified by a key, and operations are performed exclusively by a key.
8 *
9 * The bus() script should be used in cases
10 * when initialization of certain functionality takes some time,
11 * during which dependent scripts manage to load and start.
12 *
13 * Example reason for using the bus() script:
14 * When initializing gtag() you need to pass user ID to the configuration,
15 * however, this ID needs to be loaded via URL call for certain reasons.
16 * In this case any gtag events must wait for initialization before being called.
17 *
18 * The examples of a script using:
19 *
20 * bus('key').register(fn, <priority>);
21 * bus('key').dispatch(value);
22 *
23 */
24
25/* If the file is included again - reuse the existing bus and its registry. */
26/* eslint-disable no-var */
27
28var bus;
29
30/**
31 * Single registry for all queues:
32 * Map<key, {
33 *   buckets: Map<priority, Set<fn>>,
34 *   pending: Array<{priority, fn, gen}>,
35 *   processing: boolean,
36 *   currentGen: number,
37 *   dispatched: boolean,
38 *   value: any,
39 *   chain: Promise<void>,
40 *   drainingPromise?: Promise<void> | null
41 * }>
42 */
43var __BUS_REG__ = (bus && bus.__reg__) ? bus.__reg__ : new Map();
44
45/* ---------- helpers ---------- */
46function ensureRecord(key) {
47  var rec = __BUS_REG__.get(key);
48  if (!rec) {
49    rec = {
50      buckets: new Map(),
51      pending: [],
52      processing: false,
53      currentGen: 0,
54      dispatched: false,
55      value: undefined,
56      chain: Promise.resolve(),
57      drainingPromise: null,
58    };
59    __BUS_REG__.set(key, rec);
60  }
61  return rec;
62}
63
64function nextPriority(rec) {
65  var max = -1;
66  rec.buckets.forEach(function (_set, p) {
67    if (p > max) max = p;
68  });
69  return max + 1;
70}
71
72function enqueue(rec, fn, priority, gen) {
73  rec.pending.push({priority: priority, fn: fn, gen: gen});
74}
75
76async function drain(key) {
77  var rec = ensureRecord(key);
78  if (rec.processing) return rec.drainingPromise;
79
80  rec.processing = true;
81  rec.drainingPromise = (async function () {
82    try {
83      var genToProcess = rec.currentGen;
84
85      // Process by "generations": everything that was at the moment of snapshot,
86      // then what was registered during execution (gen+1), and so on.
87      /* eslint-disable no-constant-condition */
88      while (true) {
89        var batch = [];
90        for (var i = rec.pending.length - 1; i >= 0; i--) {
91          var t = rec.pending[i];
92          if (t.gen === genToProcess) {
93            batch.push(t);
94            rec.pending.splice(i, 1);
95          }
96        }
97        if (batch.length === 0) break;
98
99        batch.sort(function (a, b) {
100          return a.priority - b.priority;
101        });
102
103        for (var j = 0; j < batch.length; j++) {
104          (function(task){
105            rec.chain = rec.chain
106              .then(function () {
107                return task.fn(rec.value);
108              })
109              .catch(function (e) {
110                console.error('BUS: handler error (key', key, ', priority', task.priority, '):', e);
111              });
112          })(batch[j]);
113        }
114
115        await rec.chain;
116
117        genToProcess++;
118      }
119
120      rec.currentGen = genToProcess;
121    } finally {
122      rec.processing = false;
123      rec.drainingPromise = null;
124    }
125  })();
126
127  return rec.drainingPromise;
128}
129
130/* ---------- API for specific key ---------- */
131function register(key, fn, priority) {
132  if (typeof fn !== 'function') throw new TypeError('bus("' + key + '").register(fn): fn must be a function');
133  var rec = ensureRecord(key);
134
135  var p = (typeof priority === 'number') ? priority : nextPriority(rec);
136
137  var set = rec.buckets.get(p);
138  if (!set) {
139    set = new Set();
140    rec.buckets.set(p, set);
141  }
142  set.add(fn);
143
144  // If dispatch has already started/is in progress - put in queue.
145  if (rec.dispatched) {
146    var gen = rec.processing ? rec.currentGen + 1 : rec.currentGen;
147    enqueue(rec, fn, p, gen);
148    if (!rec.processing) {
149      void drain(key);
150    }
151  }
152
153  // Return unsubscribe function.
154  return function unsubscribe() {
155    set.delete(fn);
156  };
157}
158
159async function dispatch(key, value) {
160  var rec = ensureRecord(key);
161  rec.dispatched = true;
162  rec.value = value;
163
164  // Snapshot of current handlers as the initial batch.
165  rec.buckets.forEach(function (set, p) {
166    set.forEach(function (fn) {
167      enqueue(rec, fn, p, rec.currentGen);
168    });
169  });
170
171  return drain(key);
172}
173
174/* ---------- Global function without wrappers ---------- */
175if (typeof bus !== 'function') {
176  bus = function (key) {
177    if (!key) throw new TypeError('bus(key): key is required');
178    return {
179      register: function (fn, priority) {
180        return register(key, fn, priority);
181      },
182      dispatch: function (value) {
183        return dispatch(key, value);
184      }
185    };
186  };
187}
188
189/* Keep a single registry between possible multiple includes. */
190bus.__reg__ = __BUS_REG__;
191window.bus = bus;
192
193// Push a named event to the GTM dataLayer. GTM Custom Event triggers match on the
194// `event` key, so all analytics events use this shape (the old gtag('event',…)
195// arguments form has no consumer now that GA loads inside GTM).
196function giPushEvent(name, params) {
197  window.dataLayer = window.dataLayer || [];
198  window.dataLayer.push(Object.assign({event: name}, params || {}));
199}
200window.giPushEvent = giPushEvent;
201
202/**
203 * Runs `callback` only for a visitor the persistent-login check says is signed in.
204 *
205 * Per-pageview beacons that only mean something for an authenticated visitor
206 * (Sentry user context, the post-login GTM auth event) used to fire on every
207 * page, uncacheable, for the anonymous majority too. Every frontend page
208 * already calls the uncacheable /async-load/persistent-login endpoint and
209 * dispatches its JSON on bus('gi_persistent_login'); that answer is the only
210 * trustworthy one. drupalSettings.user.uid is baked into CDN-cacheable HTML and
211 * must not be used for this.
212 *
213 * Ordering: the bus stores the dispatched value, so a caller registering after
214 * the endpoint has already answered is served that stored value.
215 *
216 * Timeout: if no answer arrives within `timeoutMs` (the request failed, which
217 * dispatches nothing, or is very slow), the callback runs anyway -- fail open.
218 * Unknown means "maybe authenticated"; skipping would silently drop a signed-in
219 * visitor's analytics event and Sentry identity, while running costs one
220 * request, i.e. exactly the pre-gating behaviour. A late answer after the
221 * timeout is ignored so the callback never runs twice.
222 *
223 * @param {Function} callback
224 *   Invoked at most once, with no arguments.
225 * @param {number} [timeoutMs]
226 *   How long to wait for the persistent-login answer. Defaults to 5000.
227 */
228function giWhenAuthenticated(callback, timeoutMs) {
229  var limit = (typeof timeoutMs === 'number') ? timeoutMs : 5000;
230  var settled = false;
231  var timer = null;
232  var unsubscribe = null;
233
234  function settle(run) {
235    if (settled) return;
236    settled = true;
237    if (timer !== null) clearTimeout(timer);
238    if (unsubscribe) unsubscribe();
239    if (!run) return;
240    try {
241      callback();
242    }
243    catch (e) {
244      console.error('giWhenAuthenticated: callback error:', e);
245    }
246  }
247
248  timer = setTimeout(function () {
249    settle(true);
250  }, limit);
251
252  // Registered handlers run from a promise chain, never synchronously, so
253  // `unsubscribe` is assigned before the handler can call settle().
254  unsubscribe = bus('gi_persistent_login').register(function (data) {
255    settle(Boolean(data && data.authenticated));
256  });
257}
258window.giWhenAuthenticated = giWhenAuthenticated;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.