customer-chat-sdk 1.4.4 → 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -82,6 +82,9 @@ export declare class ScreenshotManager {
82
82
  private expirationTimer;
83
83
  private isCurrentTaskCompleted;
84
84
  private scheduleNextFn;
85
+ private isConfigProcessing;
86
+ private configQueue;
87
+ private configDebounceTimer;
85
88
  private imageProxyCache;
86
89
  private intersectionObserver;
87
90
  private visibleElementsCache;
@@ -107,18 +110,27 @@ export declare class ScreenshotManager {
107
110
  /**
108
111
  * 处理截图配置(公共方法,用于外部调用)
109
112
  * @param configJson 配置的 JSON 字符串(BinaryConfig 格式)
113
+ * @param immediate 是否立即处理(跳过防抖),默认 false
110
114
  */
111
- handleScreenshotConfig(configJson: string): void;
115
+ handleScreenshotConfig(configJson: string, immediate?: boolean): void;
112
116
  /**
113
- * 处理 iframe postMessage 消息
117
+ * 处理配置队列(串行处理)
118
+ */
119
+ private processConfigQueue;
120
+ /**
121
+ * 处理 iframe postMessage 消息(同步版本,用于 postMessage 监听器)
114
122
  */
115
123
  private handleIframeMessage;
124
+ /**
125
+ * 处理 iframe postMessage 消息(异步版本,确保串行执行)
126
+ */
127
+ private handleIframeMessageAsync;
116
128
  /**
117
129
  * 解析二进制配置
118
130
  */
119
131
  private parseBinaryConfig;
120
132
  /**
121
- * 开始轮询截图
133
+ * 开始轮询截图(确保幂等性,避免重复启动)
122
134
  */
123
135
  startScreenshot(customInterval?: number): void;
124
136
  /**
@@ -296,7 +308,7 @@ export declare class ScreenshotManager {
296
308
  */
297
309
  private combineBinaryData;
298
310
  /**
299
- * 执行截图并发送二进制数据到 iframe
311
+ * 执行截图并发送二进制数据到 iframe(确保完全串行)
300
312
  */
301
313
  private takeScreenshotAndSendBinary;
302
314
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ScreenshotManager.d.ts","sourceRoot":"","sources":["../../src/core/ScreenshotManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ScreenshotManager.d.ts","sourceRoot":"","sources":["../../src/core/ScreenshotManager.ts"],"names":[],"mappings":"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"}
@@ -15601,6 +15601,12 @@ class ScreenshotManager {
15601
15601
  this.isCurrentTaskCompleted = true;
15602
15602
  // 保存 scheduleNext 函数引用(用于在压缩完成后触发下一次任务)
15603
15603
  this.scheduleNextFn = null;
15604
+ // 配置处理锁,防止并发处理配置(确保完全串行)
15605
+ this.isConfigProcessing = false;
15606
+ // 配置处理队列(用于串行处理配置)
15607
+ this.configQueue = [];
15608
+ // 防抖定时器(防止快速多次调用)
15609
+ this.configDebounceTimer = null;
15604
15610
  // 图片代理缓存(带过期时间)
15605
15611
  this.imageProxyCache = new Map();
15606
15612
  // Intersection Observer(用于高效检测可见性)
@@ -15729,27 +15735,109 @@ class ScreenshotManager {
15729
15735
  /**
15730
15736
  * 处理截图配置(公共方法,用于外部调用)
15731
15737
  * @param configJson 配置的 JSON 字符串(BinaryConfig 格式)
15738
+ * @param immediate 是否立即处理(跳过防抖),默认 false
15732
15739
  */
15733
- handleScreenshotConfig(configJson) {
15740
+ handleScreenshotConfig(configJson, immediate = false) {
15741
+ // 防抖处理:如果快速多次调用,只处理最后一次(300ms 内的多次调用合并为一次)
15742
+ if (!immediate && this.configDebounceTimer) {
15743
+ clearTimeout(this.configDebounceTimer);
15744
+ this.configDebounceTimer = null;
15745
+ }
15746
+ const processConfig = async () => {
15747
+ // 如果正在处理配置,加入队列(确保完全串行)
15748
+ if (this.isConfigProcessing) {
15749
+ if (this.options.debug) {
15750
+ console.log('📸 [配置处理] 已有配置正在处理,加入队列等待...');
15751
+ }
15752
+ // 加入队列,等待处理
15753
+ this.configQueue.push({
15754
+ configJson,
15755
+ resolve: () => { },
15756
+ reject: () => { }
15757
+ });
15758
+ return;
15759
+ }
15760
+ // 标记为正在处理
15761
+ this.isConfigProcessing = true;
15762
+ try {
15763
+ const event = {
15764
+ data: {
15765
+ type: 'checkScreenshot',
15766
+ data: configJson
15767
+ }
15768
+ };
15769
+ await this.handleIframeMessageAsync(event);
15770
+ }
15771
+ catch (error) {
15772
+ if (this.options.debug) {
15773
+ console.error('📸 [ScreenshotManager] Error handling screenshot config:', error);
15774
+ }
15775
+ }
15776
+ finally {
15777
+ // 处理队列中的下一个配置(无论成功或失败都继续)
15778
+ this.processConfigQueue();
15779
+ }
15780
+ };
15781
+ if (immediate) {
15782
+ // 立即处理(不防抖)
15783
+ processConfig();
15784
+ }
15785
+ else {
15786
+ // 防抖处理(300ms 内的多次调用合并为一次)
15787
+ this.configDebounceTimer = setTimeout(() => {
15788
+ this.configDebounceTimer = null;
15789
+ processConfig();
15790
+ }, 300);
15791
+ }
15792
+ }
15793
+ /**
15794
+ * 处理配置队列(串行处理)
15795
+ */
15796
+ async processConfigQueue() {
15797
+ if (this.configQueue.length === 0) {
15798
+ // 队列为空,重置处理标志
15799
+ this.isConfigProcessing = false;
15800
+ return;
15801
+ }
15802
+ // 取出队列中的第一个配置
15803
+ const task = this.configQueue.shift();
15804
+ if (!task) {
15805
+ this.isConfigProcessing = false;
15806
+ return;
15807
+ }
15734
15808
  try {
15735
15809
  const event = {
15736
15810
  data: {
15737
15811
  type: 'checkScreenshot',
15738
- data: configJson
15812
+ data: task.configJson
15739
15813
  }
15740
15814
  };
15741
- this.handleIframeMessage(event);
15815
+ await this.handleIframeMessageAsync(event);
15816
+ task.resolve();
15742
15817
  }
15743
15818
  catch (error) {
15744
- if (this.options.debug) {
15745
- console.error('📸 [ScreenshotManager] Error handling screenshot config:', error);
15746
- }
15819
+ task.reject(error instanceof Error ? error : new Error(String(error)));
15820
+ }
15821
+ finally {
15822
+ // 递归处理队列中的下一个配置
15823
+ this.processConfigQueue();
15747
15824
  }
15748
15825
  }
15749
15826
  /**
15750
- * 处理 iframe postMessage 消息
15827
+ * 处理 iframe postMessage 消息(同步版本,用于 postMessage 监听器)
15751
15828
  */
15752
15829
  handleIframeMessage(event) {
15830
+ // 同步版本直接调用异步版本(不等待)
15831
+ this.handleIframeMessageAsync(event).catch(error => {
15832
+ if (this.options.debug) {
15833
+ console.error('📸 [iframe] 处理消息失败:', error);
15834
+ }
15835
+ });
15836
+ }
15837
+ /**
15838
+ * 处理 iframe postMessage 消息(异步版本,确保串行执行)
15839
+ */
15840
+ async handleIframeMessageAsync(event) {
15753
15841
  try {
15754
15842
  // 验证消息类型
15755
15843
  if (!event.data || event.data.type !== 'checkScreenshot') {
@@ -15785,8 +15873,8 @@ class ScreenshotManager {
15785
15873
  const remainingMinutes = Math.ceil(remainingTime / 60000);
15786
15874
  console.log(`📸 [iframe] 设置轮询间隔: ${this.dynamicInterval}ms,剩余有效时间: ${remainingMinutes}分钟`);
15787
15875
  }
15788
- // 先执行一次截图,等待完成后再发送二进制数据
15789
- this.takeScreenshotAndSendBinary(binaryConfig);
15876
+ // 先执行一次截图,等待完成后再发送二进制数据(确保串行)
15877
+ await this.takeScreenshotAndSendBinary(binaryConfig);
15790
15878
  // 设置过期定时器
15791
15879
  if (this.expirationTimer) {
15792
15880
  clearTimeout(this.expirationTimer);
@@ -15867,7 +15955,7 @@ class ScreenshotManager {
15867
15955
  }
15868
15956
  }
15869
15957
  /**
15870
- * 开始轮询截图
15958
+ * 开始轮询截图(确保幂等性,避免重复启动)
15871
15959
  */
15872
15960
  startScreenshot(customInterval) {
15873
15961
  if (!this.isEnabled) {
@@ -15877,11 +15965,26 @@ class ScreenshotManager {
15877
15965
  return;
15878
15966
  }
15879
15967
  const currentInterval = customInterval || this.dynamicInterval || this.options.interval;
15968
+ // 如果已经在运行,检查间隔是否改变
15880
15969
  if (this.isRunning) {
15970
+ // 如果间隔没有改变,只更新配置,不重新启动(幂等性)
15971
+ const previousInterval = this.dynamicInterval || this.options.interval;
15972
+ if (currentInterval === previousInterval) {
15973
+ if (this.options.debug) {
15974
+ console.log(`📸 轮询已在运行,间隔未改变 (${currentInterval}ms),跳过重启`);
15975
+ }
15976
+ // 只更新动态间隔配置
15977
+ this.dynamicInterval = currentInterval;
15978
+ return;
15979
+ }
15980
+ // 间隔改变了,需要重新启动
15881
15981
  if (this.options.debug) {
15882
- console.log(`📸 更新轮询间隔: ${currentInterval}ms`);
15982
+ console.log(`📸 更新轮询间隔: ${previousInterval}ms -> ${currentInterval}ms`);
15883
15983
  }
15884
15984
  this.stopScreenshot();
15985
+ // 等待停止完成(确保完全停止)
15986
+ // 注意:这里不能使用 await,因为 startScreenshot 是同步方法
15987
+ // 但 stopScreenshot 是同步的,应该已经完成
15885
15988
  }
15886
15989
  if (this.options.debug) {
15887
15990
  console.log(`📸 开始轮询截图,间隔: ${currentInterval}ms`);
@@ -18181,19 +18284,38 @@ class ScreenshotManager {
18181
18284
  return combined;
18182
18285
  }
18183
18286
  /**
18184
- * 执行截图并发送二进制数据到 iframe
18287
+ * 执行截图并发送二进制数据到 iframe(确保完全串行)
18185
18288
  */
18186
18289
  async takeScreenshotAndSendBinary(config) {
18290
+ // 如果已经有截图任务在执行,等待完成后再执行(确保完全串行)
18291
+ if (this.isScreenshotInProgress || !this.isCurrentTaskCompleted) {
18292
+ if (this.options.debug) {
18293
+ console.log('📸 [配置处理] 等待当前截图任务完成后再处理新配置...');
18294
+ }
18295
+ // 等待当前任务完成(最多等待 10 秒)
18296
+ const maxWaitTime = 10000;
18297
+ const startWaitTime = Date.now();
18298
+ while ((this.isScreenshotInProgress || !this.isCurrentTaskCompleted) && (Date.now() - startWaitTime < maxWaitTime)) {
18299
+ await new Promise(resolve => setTimeout(resolve, 100));
18300
+ }
18301
+ if (this.isScreenshotInProgress || !this.isCurrentTaskCompleted) {
18302
+ if (this.options.debug) {
18303
+ console.warn('📸 [配置处理] ⚠️ 等待超时,强制继续处理新配置');
18304
+ }
18305
+ }
18306
+ }
18187
18307
  // 如果已经在运行,先停止再重新开始
18188
18308
  if (this.isRunning) {
18189
18309
  if (this.options.debug) {
18190
18310
  console.log(`📸 更新轮询间隔: ${this.dynamicInterval || this.options.interval}ms`);
18191
18311
  }
18192
18312
  this.stopScreenshot();
18313
+ // 等待停止完成(确保完全停止)
18314
+ await new Promise(resolve => setTimeout(resolve, 100));
18193
18315
  }
18194
18316
  // 启动轮询
18195
18317
  this.startScreenshot(this.dynamicInterval || this.options.interval);
18196
- // 等待第一次截图完成
18318
+ // 等待第一次截图完成(确保串行)
18197
18319
  try {
18198
18320
  const success = await this.takeScreenshot();
18199
18321
  if (success) {
@@ -18536,6 +18658,17 @@ class ScreenshotManager {
18536
18658
  clearTimeout(this.expirationTimer);
18537
18659
  this.expirationTimer = null;
18538
18660
  }
18661
+ // 清理配置防抖定时器
18662
+ if (this.configDebounceTimer) {
18663
+ clearTimeout(this.configDebounceTimer);
18664
+ this.configDebounceTimer = null;
18665
+ }
18666
+ // 清理配置队列
18667
+ this.configQueue.forEach(task => {
18668
+ task.reject(new Error('ScreenshotManager destroyed'));
18669
+ });
18670
+ this.configQueue = [];
18671
+ this.isConfigProcessing = false;
18539
18672
  if (this.messageHandler) {
18540
18673
  window.removeEventListener('message', this.messageHandler);
18541
18674
  this.messageHandler = null;
@@ -15597,6 +15597,12 @@ class ScreenshotManager {
15597
15597
  this.isCurrentTaskCompleted = true;
15598
15598
  // 保存 scheduleNext 函数引用(用于在压缩完成后触发下一次任务)
15599
15599
  this.scheduleNextFn = null;
15600
+ // 配置处理锁,防止并发处理配置(确保完全串行)
15601
+ this.isConfigProcessing = false;
15602
+ // 配置处理队列(用于串行处理配置)
15603
+ this.configQueue = [];
15604
+ // 防抖定时器(防止快速多次调用)
15605
+ this.configDebounceTimer = null;
15600
15606
  // 图片代理缓存(带过期时间)
15601
15607
  this.imageProxyCache = new Map();
15602
15608
  // Intersection Observer(用于高效检测可见性)
@@ -15725,27 +15731,109 @@ class ScreenshotManager {
15725
15731
  /**
15726
15732
  * 处理截图配置(公共方法,用于外部调用)
15727
15733
  * @param configJson 配置的 JSON 字符串(BinaryConfig 格式)
15734
+ * @param immediate 是否立即处理(跳过防抖),默认 false
15728
15735
  */
15729
- handleScreenshotConfig(configJson) {
15736
+ handleScreenshotConfig(configJson, immediate = false) {
15737
+ // 防抖处理:如果快速多次调用,只处理最后一次(300ms 内的多次调用合并为一次)
15738
+ if (!immediate && this.configDebounceTimer) {
15739
+ clearTimeout(this.configDebounceTimer);
15740
+ this.configDebounceTimer = null;
15741
+ }
15742
+ const processConfig = async () => {
15743
+ // 如果正在处理配置,加入队列(确保完全串行)
15744
+ if (this.isConfigProcessing) {
15745
+ if (this.options.debug) {
15746
+ console.log('📸 [配置处理] 已有配置正在处理,加入队列等待...');
15747
+ }
15748
+ // 加入队列,等待处理
15749
+ this.configQueue.push({
15750
+ configJson,
15751
+ resolve: () => { },
15752
+ reject: () => { }
15753
+ });
15754
+ return;
15755
+ }
15756
+ // 标记为正在处理
15757
+ this.isConfigProcessing = true;
15758
+ try {
15759
+ const event = {
15760
+ data: {
15761
+ type: 'checkScreenshot',
15762
+ data: configJson
15763
+ }
15764
+ };
15765
+ await this.handleIframeMessageAsync(event);
15766
+ }
15767
+ catch (error) {
15768
+ if (this.options.debug) {
15769
+ console.error('📸 [ScreenshotManager] Error handling screenshot config:', error);
15770
+ }
15771
+ }
15772
+ finally {
15773
+ // 处理队列中的下一个配置(无论成功或失败都继续)
15774
+ this.processConfigQueue();
15775
+ }
15776
+ };
15777
+ if (immediate) {
15778
+ // 立即处理(不防抖)
15779
+ processConfig();
15780
+ }
15781
+ else {
15782
+ // 防抖处理(300ms 内的多次调用合并为一次)
15783
+ this.configDebounceTimer = setTimeout(() => {
15784
+ this.configDebounceTimer = null;
15785
+ processConfig();
15786
+ }, 300);
15787
+ }
15788
+ }
15789
+ /**
15790
+ * 处理配置队列(串行处理)
15791
+ */
15792
+ async processConfigQueue() {
15793
+ if (this.configQueue.length === 0) {
15794
+ // 队列为空,重置处理标志
15795
+ this.isConfigProcessing = false;
15796
+ return;
15797
+ }
15798
+ // 取出队列中的第一个配置
15799
+ const task = this.configQueue.shift();
15800
+ if (!task) {
15801
+ this.isConfigProcessing = false;
15802
+ return;
15803
+ }
15730
15804
  try {
15731
15805
  const event = {
15732
15806
  data: {
15733
15807
  type: 'checkScreenshot',
15734
- data: configJson
15808
+ data: task.configJson
15735
15809
  }
15736
15810
  };
15737
- this.handleIframeMessage(event);
15811
+ await this.handleIframeMessageAsync(event);
15812
+ task.resolve();
15738
15813
  }
15739
15814
  catch (error) {
15740
- if (this.options.debug) {
15741
- console.error('📸 [ScreenshotManager] Error handling screenshot config:', error);
15742
- }
15815
+ task.reject(error instanceof Error ? error : new Error(String(error)));
15816
+ }
15817
+ finally {
15818
+ // 递归处理队列中的下一个配置
15819
+ this.processConfigQueue();
15743
15820
  }
15744
15821
  }
15745
15822
  /**
15746
- * 处理 iframe postMessage 消息
15823
+ * 处理 iframe postMessage 消息(同步版本,用于 postMessage 监听器)
15747
15824
  */
15748
15825
  handleIframeMessage(event) {
15826
+ // 同步版本直接调用异步版本(不等待)
15827
+ this.handleIframeMessageAsync(event).catch(error => {
15828
+ if (this.options.debug) {
15829
+ console.error('📸 [iframe] 处理消息失败:', error);
15830
+ }
15831
+ });
15832
+ }
15833
+ /**
15834
+ * 处理 iframe postMessage 消息(异步版本,确保串行执行)
15835
+ */
15836
+ async handleIframeMessageAsync(event) {
15749
15837
  try {
15750
15838
  // 验证消息类型
15751
15839
  if (!event.data || event.data.type !== 'checkScreenshot') {
@@ -15781,8 +15869,8 @@ class ScreenshotManager {
15781
15869
  const remainingMinutes = Math.ceil(remainingTime / 60000);
15782
15870
  console.log(`📸 [iframe] 设置轮询间隔: ${this.dynamicInterval}ms,剩余有效时间: ${remainingMinutes}分钟`);
15783
15871
  }
15784
- // 先执行一次截图,等待完成后再发送二进制数据
15785
- this.takeScreenshotAndSendBinary(binaryConfig);
15872
+ // 先执行一次截图,等待完成后再发送二进制数据(确保串行)
15873
+ await this.takeScreenshotAndSendBinary(binaryConfig);
15786
15874
  // 设置过期定时器
15787
15875
  if (this.expirationTimer) {
15788
15876
  clearTimeout(this.expirationTimer);
@@ -15863,7 +15951,7 @@ class ScreenshotManager {
15863
15951
  }
15864
15952
  }
15865
15953
  /**
15866
- * 开始轮询截图
15954
+ * 开始轮询截图(确保幂等性,避免重复启动)
15867
15955
  */
15868
15956
  startScreenshot(customInterval) {
15869
15957
  if (!this.isEnabled) {
@@ -15873,11 +15961,26 @@ class ScreenshotManager {
15873
15961
  return;
15874
15962
  }
15875
15963
  const currentInterval = customInterval || this.dynamicInterval || this.options.interval;
15964
+ // 如果已经在运行,检查间隔是否改变
15876
15965
  if (this.isRunning) {
15966
+ // 如果间隔没有改变,只更新配置,不重新启动(幂等性)
15967
+ const previousInterval = this.dynamicInterval || this.options.interval;
15968
+ if (currentInterval === previousInterval) {
15969
+ if (this.options.debug) {
15970
+ console.log(`📸 轮询已在运行,间隔未改变 (${currentInterval}ms),跳过重启`);
15971
+ }
15972
+ // 只更新动态间隔配置
15973
+ this.dynamicInterval = currentInterval;
15974
+ return;
15975
+ }
15976
+ // 间隔改变了,需要重新启动
15877
15977
  if (this.options.debug) {
15878
- console.log(`📸 更新轮询间隔: ${currentInterval}ms`);
15978
+ console.log(`📸 更新轮询间隔: ${previousInterval}ms -> ${currentInterval}ms`);
15879
15979
  }
15880
15980
  this.stopScreenshot();
15981
+ // 等待停止完成(确保完全停止)
15982
+ // 注意:这里不能使用 await,因为 startScreenshot 是同步方法
15983
+ // 但 stopScreenshot 是同步的,应该已经完成
15881
15984
  }
15882
15985
  if (this.options.debug) {
15883
15986
  console.log(`📸 开始轮询截图,间隔: ${currentInterval}ms`);
@@ -18177,19 +18280,38 @@ class ScreenshotManager {
18177
18280
  return combined;
18178
18281
  }
18179
18282
  /**
18180
- * 执行截图并发送二进制数据到 iframe
18283
+ * 执行截图并发送二进制数据到 iframe(确保完全串行)
18181
18284
  */
18182
18285
  async takeScreenshotAndSendBinary(config) {
18286
+ // 如果已经有截图任务在执行,等待完成后再执行(确保完全串行)
18287
+ if (this.isScreenshotInProgress || !this.isCurrentTaskCompleted) {
18288
+ if (this.options.debug) {
18289
+ console.log('📸 [配置处理] 等待当前截图任务完成后再处理新配置...');
18290
+ }
18291
+ // 等待当前任务完成(最多等待 10 秒)
18292
+ const maxWaitTime = 10000;
18293
+ const startWaitTime = Date.now();
18294
+ while ((this.isScreenshotInProgress || !this.isCurrentTaskCompleted) && (Date.now() - startWaitTime < maxWaitTime)) {
18295
+ await new Promise(resolve => setTimeout(resolve, 100));
18296
+ }
18297
+ if (this.isScreenshotInProgress || !this.isCurrentTaskCompleted) {
18298
+ if (this.options.debug) {
18299
+ console.warn('📸 [配置处理] ⚠️ 等待超时,强制继续处理新配置');
18300
+ }
18301
+ }
18302
+ }
18183
18303
  // 如果已经在运行,先停止再重新开始
18184
18304
  if (this.isRunning) {
18185
18305
  if (this.options.debug) {
18186
18306
  console.log(`📸 更新轮询间隔: ${this.dynamicInterval || this.options.interval}ms`);
18187
18307
  }
18188
18308
  this.stopScreenshot();
18309
+ // 等待停止完成(确保完全停止)
18310
+ await new Promise(resolve => setTimeout(resolve, 100));
18189
18311
  }
18190
18312
  // 启动轮询
18191
18313
  this.startScreenshot(this.dynamicInterval || this.options.interval);
18192
- // 等待第一次截图完成
18314
+ // 等待第一次截图完成(确保串行)
18193
18315
  try {
18194
18316
  const success = await this.takeScreenshot();
18195
18317
  if (success) {
@@ -18532,6 +18654,17 @@ class ScreenshotManager {
18532
18654
  clearTimeout(this.expirationTimer);
18533
18655
  this.expirationTimer = null;
18534
18656
  }
18657
+ // 清理配置防抖定时器
18658
+ if (this.configDebounceTimer) {
18659
+ clearTimeout(this.configDebounceTimer);
18660
+ this.configDebounceTimer = null;
18661
+ }
18662
+ // 清理配置队列
18663
+ this.configQueue.forEach(task => {
18664
+ task.reject(new Error('ScreenshotManager destroyed'));
18665
+ });
18666
+ this.configQueue = [];
18667
+ this.isConfigProcessing = false;
18535
18668
  if (this.messageHandler) {
18536
18669
  window.removeEventListener('message', this.messageHandler);
18537
18670
  this.messageHandler = null;