handlers.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import { log, error, time, timeEnd } from './utils.js';
  2. /*
  3. 管理所有事件处理函数,并生成一个代理函数,允许用户替换其中的某些实现
  4. 受制于小程序的运行时机制,在 locked 之后,不允许变更 handlerNames
  5. */
  6. var HandlersController = /** @class */ (function () {
  7. function HandlersController(elementTag) {
  8. if (elementTag === void 0) { elementTag = ''; }
  9. this.elementTag = ''; // 主要是 debug 使用
  10. this.locked = false; // 是否已经锁定,锁定之后不允许新增 handler
  11. this.executionInProgress = false;
  12. this.executionQueue = [];
  13. this.handlerNames = [];
  14. this.handlerImpl = {};
  15. this.elementTag = elementTag;
  16. }
  17. HandlersController.prototype.addHandler = function (name, bindContext, impl, disableMultiImpl) {
  18. var _this = this;
  19. if (this.locked && this.handlerNames.indexOf(name) < 0) {
  20. throw new Error("\u4E0D\u5141\u8BB8\u52A8\u6001\u65B0\u589E handler: ".concat(name));
  21. }
  22. if (impl && !bindContext) {
  23. throw new Error("bindContext \u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u8FD0\u884C\u65F6\u9700\u8981\u7528\u5230\u5B83");
  24. }
  25. if (bindContext && !impl) {
  26. throw new Error('missing impl');
  27. }
  28. if (typeof name !== 'string') {
  29. throw new Error("name \u7684\u7C7B\u578B\u4E0D\u5408\u6CD5\uFF08".concat(typeof name, "\uFF09\uFF0C\u5B83\u5E94\u8BE5\u662F\u4E00\u4E2A\u5B57\u7B26\u4E32"));
  30. }
  31. else if (typeof impl !== 'function' && typeof impl !== 'undefined') {
  32. throw new Error("impl \u7684\u7C7B\u578B\u4E0D\u5408\u6CD5\uFF08".concat(typeof impl, "\uFF09\uFF0C\u5B83\u5E94\u8BE5\u662F\u4E00\u4E2A\u51FD\u6570"));
  33. }
  34. if (this.handlerNames.indexOf(name) < 0) {
  35. this.handlerNames.push(name);
  36. }
  37. this.handlerImpl[name] = this.handlerImpl[name] || [];
  38. var self = this;
  39. if (!impl) {
  40. return function () { };
  41. }
  42. if (disableMultiImpl &&
  43. this.getHandlersByName(name, bindContext).length > 0) {
  44. throw new Error("".concat(name, " \u5DF2\u7ECF\u6CE8\u518C\u4E86\u4E00\u4E2A\u5B9E\u73B0\uFF0C\u4E0D\u80FD\u518D\u65B0\u589E"));
  45. }
  46. var implInfo = {
  47. // 裹一层,把 off 方法收集下来
  48. fn: function () {
  49. var args = [];
  50. for (var _i = 0; _i < arguments.length; _i++) {
  51. args[_i] = arguments[_i];
  52. }
  53. if (!this)
  54. throw new Error('missing context, cannot find matching handler');
  55. var ctx = self.filterContext(bindContext, this);
  56. // context 不匹配,不处理
  57. if (!ctx)
  58. throw new Error('handler context mismatch, refuse executing');
  59. try {
  60. var ret = impl.apply(this, args);
  61. if (typeof ret === 'function') {
  62. implInfo.off = ret; // 这个 off 其实已经不用了
  63. }
  64. else {
  65. return ret; // 如果不是 function,认为这个返回值有用,不是 off
  66. }
  67. }
  68. catch (e) {
  69. error("".concat(self.elementTag, " ").concat(name, " \u6267\u884C\u51FA\u9519\uFF0C\u9519\u8BEF\u4FE1\u606F\uFF1A").concat(e.message));
  70. throw e;
  71. }
  72. },
  73. bindContext: bindContext,
  74. };
  75. this.handlerImpl[name].push(implInfo);
  76. return function () {
  77. log("off ".concat(name, " - ").concat(_this.elementTag));
  78. var handlers = _this.handlerImpl[name]; // 这里闭包里有明确的 implInfo, 不需要根据 context 过滤
  79. if (!handlers) {
  80. var msg = "\u6CA1\u6709\u627E\u5230 ".concat(name, " \u5BF9\u5E94\u7684\u5B9E\u73B0\uFF0C\u662F\u5426\u5DF2\u7ECF\u88AB reset \u4E86 \uFF1F\u8BF7\u68C0\u67E5\u751F\u547D\u5468\u671F\u6D41\u7A0B");
  81. error(msg);
  82. throw new Error(msg);
  83. }
  84. var index = handlers.indexOf(implInfo);
  85. var offFunction = handlers[index].off;
  86. if (offFunction) {
  87. try {
  88. offFunction.call(undefined);
  89. }
  90. catch (e) {
  91. error("\u6267\u884C ".concat(name, " \u7684\u53CD\u6CE8\u518C\u65B9\u6CD5\u65F6\u51FA\u9519\uFF1A"));
  92. error(e);
  93. throw e;
  94. }
  95. }
  96. if (index >= 0) {
  97. handlers.splice(index, 1);
  98. }
  99. };
  100. };
  101. HandlersController.prototype.lockHandlerNames = function () {
  102. this.locked = true;
  103. };
  104. HandlersController.prototype.resetAllImpl = function () {
  105. this.handlerImpl = {};
  106. };
  107. HandlersController.prototype.getHandlersByName = function (name, context) {
  108. var _this = this;
  109. if (!context)
  110. throw new Error('context is required');
  111. return this.handlerImpl[name].filter(function (handler) {
  112. return _this.filterContext(handler.bindContext, context);
  113. });
  114. };
  115. HandlersController.prototype.callHandlers = function (name, context, args) {
  116. var controller = this;
  117. var handlers = (controller.handlerImpl[name] || []).filter(function (handler) {
  118. var targetCtx = controller.filterContext(handler === null || handler === void 0 ? void 0 : handler.bindContext, context);
  119. return !!targetCtx;
  120. }); // 过滤并复制出来,防止执行过程中有人往里面塞东西造成乱序
  121. var callId = "".concat(controller.elementTag, "-handlerCalled-").concat(name, "-").concat(Math.floor(Math.random() * 1000));
  122. var tipText = "".concat(callId, " - handlers count ").concat(handlers.length);
  123. log(Date.now(), tipText);
  124. var returnValue;
  125. for (var i = 0; i < handlers.length; i++) {
  126. log(Date.now(), "".concat(tipText, " - executing ").concat(i + 1, "/").concat(handlers.length));
  127. time(callId);
  128. var handler = handlers[i];
  129. var ret = handler.fn.apply(context, args);
  130. if (i === 0) {
  131. // 只返回第一个
  132. returnValue = ret;
  133. }
  134. timeEnd(callId);
  135. }
  136. return returnValue;
  137. };
  138. // 返回给 appx 的可能是一个 Promise,无论 appx 等不等,这里都会串行执行
  139. HandlersController.prototype.getHandlersImplProxy = function () {
  140. var _this = this;
  141. if (!this.locked) {
  142. throw new Error('please lock the handler names first');
  143. }
  144. var handlers = this.handlerNames.reduce(function (acc, handlerName) {
  145. var controller = _this;
  146. //@ts-expect-error
  147. acc[handlerName] = function () {
  148. var args = [];
  149. for (var _i = 0; _i < arguments.length; _i++) {
  150. args[_i] = arguments[_i];
  151. }
  152. // 这里要保留调用方的 this
  153. var appxCaller = this;
  154. if (!appxCaller) {
  155. console.warn('cannot find appx caller instance');
  156. }
  157. // deriveData 的时候,异步可能会有问题,直接改同步看看疗效
  158. var err;
  159. var ret;
  160. try {
  161. ret = controller.callHandlers(handlerName, appxCaller, args);
  162. }
  163. catch (e) {
  164. err = e;
  165. }
  166. // await unlock();
  167. // 防止后续所有事情被死锁
  168. if (err)
  169. throw err;
  170. // setTimeout(() => {
  171. // unlock();
  172. // }, 0);
  173. return ret;
  174. // return Promise.resolve(
  175. // (async () => {
  176. // })(),
  177. // );
  178. };
  179. return acc;
  180. }, {});
  181. return handlers;
  182. };
  183. //@ts-expect-error
  184. HandlersController.prototype.filterContext = function (bindContext, nowContext) {
  185. if (typeof bindContext === 'function') {
  186. if (!bindContext(nowContext)) {
  187. return false;
  188. }
  189. }
  190. else if (bindContext !== nowContext) {
  191. return false;
  192. }
  193. return nowContext;
  194. };
  195. return HandlersController;
  196. }());
  197. export default HandlersController;