postmessage-duplexpostmessage-duplex
首页
指南
API
示例
🎮 Playground
  • FAQ
  • 更新日志
  • GitHub
  • 简体中文
  • English
GitHub
首页
指南
API
示例
🎮 Playground
  • FAQ
  • 更新日志
  • GitHub
  • 简体中文
  • English
GitHub
  • API 参考

    • API 参考
    • IframeChannel
    • ServiceWorkerChannel
    • 类型定义
    • 错误处理

错误处理

postmessage-duplex 提供了结构化的错误处理机制。

ChannelError

自定义错误类,包含错误码和详细信息。

class ChannelError extends Error {
  /** 错误码 */
  code: ErrorCode
  
  /** 详细信息 */
  details?: Record<string, any>
  
  constructor(
    message: string, 
    code: ErrorCode, 
    details?: Record<string, any>
  )
  
  /** 转换为 JSON 对象 */
  toJSON(): {
    name: string
    message: string
    code: ErrorCode
    details?: Record<string, any>
  }
}

示例

import { ChannelError, ErrorCode } from 'postmessage-duplex'

try {
  await channel.publish('test')
} catch (error) {
  if (error instanceof ChannelError) {
    console.log('错误码:', error.code)
    console.log('错误信息:', error.message)
    console.log('详细信息:', error.details)
    console.log('JSON:', error.toJSON())
  }
}

ErrorCode

错误码枚举。

enum ErrorCode {
  /** 通道已销毁 */
  ConnectionDestroyed = 'CONNECTION_DESTROYED',
  
  /** 连接超时 */
  ConnectionTimeout = 'CONNECTION_TIMEOUT',
  
  /** 方法调用超时 */
  MethodCallTimeout = 'METHOD_CALL_TIMEOUT',
  
  /** 方法未找到 */
  MethodNotFound = 'METHOD_NOT_FOUND',
  
  /** 传输失败 */
  TransmissionFailed = 'TRANSMISSION_FAILED',
  
  /** 消息大小超限 */
  MessageSizeExceeded = 'MESSAGE_SIZE_EXCEEDED',
  
  /** 速率限制 */
  RateLimitExceeded = 'RATE_LIMIT_EXCEEDED',
  
  /** 处理器错误 */
  HandlerError = 'HANDLER_ERROR',
  
  /** 无效消息 */
  InvalidMessage = 'INVALID_MESSAGE',
  
  /** Origin 不匹配 */
  OriginMismatch = 'ORIGIN_MISMATCH'
}

错误码说明

错误码描述常见原因
ConnectionDestroyed通道已被销毁在调用 destroy() 后继续使用通道
ConnectionTimeout连接建立超时iframe 加载失败或 Service Worker 未就绪
MethodCallTimeout方法调用超时远程处理时间过长或未响应
MethodNotFound方法未找到远程端未订阅该事件
TransmissionFailed传输失败postMessage 调用失败
MessageSizeExceeded消息大小超限消息超过 maxMessageSize 设置
RateLimitExceeded速率限制消息发送频率超过 rateLimit 设置
HandlerError处理器错误远程回调函数抛出异常
InvalidMessage无效消息消息格式不正确
OriginMismatchOrigin 不匹配消息来源与预期 origin 不一致

工厂函数

createConnectionDestroyedError

创建连接已销毁错误。

function createConnectionDestroyedError(): ChannelError

示例:

import { createConnectionDestroyedError } from 'postmessage-duplex'

if (channel.isDestroyed) {
  throw createConnectionDestroyedError()
}

createTimeoutError

创建超时错误。

function createTimeoutError(
  cmdname: string, 
  timeout: number
): ChannelError

示例:

import { createTimeoutError } from 'postmessage-duplex'

throw createTimeoutError('getData', 5000)
// ChannelError: Method call 'getData' timed out after 5000ms

createHandlerError

创建处理器错误。

function createHandlerError(
  cmdname: string, 
  originalError: Error
): ChannelError

示例:

import { createHandlerError } from 'postmessage-duplex'

try {
  await handler(data)
} catch (error) {
  throw createHandlerError('getData', error as Error)
}

错误处理最佳实践

基于返回码的处理

import { ReturnCode } from 'postmessage-duplex'

const response = await channel.publish('getData', { id: 1 })

switch (response.ret) {
  case ReturnCode.Success:
    console.log('成功:', response.data)
    break
    
  case ReturnCode.TimeOut:
    console.error('请求超时,请稍后重试')
    break
    
  case ReturnCode.NoSubscribe:
    console.error('远程端未处理此请求')
    break
    
  case ReturnCode.ReceiverCallbackError:
    console.error('远程处理错误:', response.msg)
    break
    
  default:
    console.error('未知错误:', response)
}

基于异常的处理

import { ChannelError, ErrorCode } from 'postmessage-duplex'

try {
  await channel.publish('getData', { id: 1 })
} catch (error) {
  if (error instanceof ChannelError) {
    switch (error.code) {
      case ErrorCode.ConnectionDestroyed:
        // 重新创建通道
        channel = new IframeChannel(iframe)
        break
        
      case ErrorCode.MethodCallTimeout:
        // 重试或提示用户
        showRetryDialog()
        break
        
      case ErrorCode.RateLimitExceeded:
        // 延迟重试
        await delay(1000)
        retry()
        break
        
      default:
        // 记录错误
        logError(error)
    }
  } else {
    // 非通道错误
    throw error
  }
}

类型守卫

function isChannelError(error: unknown): error is ChannelError {
  return error instanceof ChannelError
}

function isTimeoutError(error: unknown): boolean {
  return isChannelError(error) && error.code === ErrorCode.MethodCallTimeout
}

// 使用
try {
  await channel.publish('test')
} catch (error) {
  if (isTimeoutError(error)) {
    // 处理超时
  }
}

统一错误处理

class ChannelClient {
  private channel: IframeChannel
  
  async request<T>(cmdname: string, data?: any): Promise<T> {
    if (this.channel.isDestroyed) {
      throw createConnectionDestroyedError()
    }
    
    const response = await this.channel.publish(cmdname, data)
    
    if (response.ret === ReturnCode.Success) {
      return response.data as T
    }
    
    // 统一转换为 ChannelError
    throw this.createError(response)
  }
  
  private createError(response: PostResponse): ChannelError {
    switch (response.ret) {
      case ReturnCode.TimeOut:
        return new ChannelError(
          'Request timed out',
          ErrorCode.MethodCallTimeout
        )
        
      case ReturnCode.NoSubscribe:
        return new ChannelError(
          'Method not found',
          ErrorCode.MethodNotFound
        )
        
      case ReturnCode.ReceiverCallbackError:
        return new ChannelError(
          response.msg || 'Handler error',
          ErrorCode.HandlerError
        )
        
      default:
        return new ChannelError(
          response.msg || 'Unknown error',
          ErrorCode.TransmissionFailed
        )
    }
  }
}
在 GitHub 上编辑此页
上次更新: 2026/1/26 09:07
贡献者: liquidliang
Prev
类型定义