فهرست منبع

fix: async error handling in Callback

tophf 1 ماه پیش
والد
کامیت
8288e606bb
4فایلهای تغییر یافته به همراه23 افزوده شده و 9 حذف شده
  1. 5 0
      src/injected/util/index.js
  2. 15 6
      src/injected/web/bridge.js
  3. 2 2
      src/injected/web/index.js
  4. 1 1
      src/injected/web/requests.js

+ 5 - 0
src/injected/util/index.js

@@ -13,6 +13,11 @@ export * from '@/common/consts';
 
 export const CONSOLE_METHODS = ['log', 'info', 'warn', ERROR, 'debug'];
 
+export const addErrorStack = (err, localErr) => {
+  err.stack += '\n-----------\n' + localErr.stack;
+  return err;
+};
+
 export const fireBridgeEvent = (eventId, msg) => {
   const detail = cloneInto ? cloneInto(msg, document) : msg;
   const evtMain = new SafeCustomEvent(eventId, { __proto__: null, detail });

+ 15 - 6
src/injected/web/bridge.js

@@ -1,3 +1,5 @@
+import { addErrorStack } from '../util';
+
 const handlers = createNullObj();
 export const addHandlers = obj => assign(handlers, obj);
 export const callbacks = createNullObj();
@@ -21,24 +23,31 @@ const bridge = {
       cb = resolve;
     });
     if (IS_FIREFOX) setPrototypeOf(res, SafePromiseConstructor);
-    postWithCallback(cmd, data, node, cb, true);
+    postWithCallback(cmd, data, node, cb);
     return res;
   },
-  /** @return {?} synchronous */
   call: postWithCallback,
 };
 
-
-function postWithCallback(cmd, data, node, cb, isPromise) {
+/**
+ * @param {string} cmd
+ * @param {any} data
+ * @param {Node} [node]
+ * @param {(this: Node, res: any, err?: Error) => any} [cb] - callback
+ * @param {boolean} [cbAsync] - to keep the original callstack in the async error provided to `cb`,
+ *                              note that Promise already tracks the caller in modern browsers.
+ * @return {any} the result in synchronous mode (no `cb`)
+ */
+function postWithCallback(cmd, data, node, cb, cbAsync) {
   let res, err;
   const id = safeGetUniqId();
   callbacks[id] = [
     cb || ((a, b) => { res = a; err = b; }),
-    !isPromise && new SafeError().stack, // Promise already tracks the caller
+    cbAsync && new SafeError(),
   ];
   bridge.post(cmd, { [CALLBACK_ID]: id, data }, node);
   if (!cb) {
-    if (err) throw err;
+    if (err) throw addErrorStack(err, new SafeError());
     return res;
   }
 }

+ 2 - 2
src/injected/web/index.js

@@ -6,7 +6,7 @@ import './gm-values';
 import './notifications';
 import './requests';
 import './tabs';
-import { bindEvents, CONSOLE_METHODS } from '../util';
+import { addErrorStack, bindEvents, CONSOLE_METHODS } from '../util';
 import { safeConcat } from './util';
 
 // Make sure to call safe::methods() in code that may run after userscripts
@@ -65,7 +65,7 @@ addHandlers({
     const cb = callbacks[id];
     delete callbacks[id];
     if (cb) {
-      if (err && cb[1]) err.stack += '\n-----------\n' + cb[1];
+      if (err && cb[1]) addErrorStack(err, cb[1]);
       this::cb[0](res, err);
     } else if (err) {
       throw err;

+ 1 - 1
src/injected/web/requests.js

@@ -240,7 +240,7 @@ export function onRequestCreate(opts, context, fileName) {
     [kResponseType]: type,
     [kXhrType]: req[kXhrType] = XHR_TYPES[type] ? type : '',
     events,
-  }, opts, OPTS_TO_PASS));
+  }, opts, OPTS_TO_PASS), null, null, /*cbAsync=*/true);
   if (!res) res = {};
   else if (IS_FIREFOX) setPrototypeOf(res, SafePromiseConstructor);
   setOwnProp(res, 'abort', () => bridge.post('AbortRequest', id));