# @cartridge/penpal 中文文档

规范地址：https://npmcn.com/package/%40cartridge/penpal/

版本：6\.2\.4
npm 元数据更新时间：2026-02-06T14:12:16.141Z
中文译文更新时间：2026-11-09T03:49:49.625Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40cartridge/penpal
原文对照：https://npmcn.com/package/%40cartridge/penpal/?lang=original
项目主页：https://github.com/Aaronius/penpal#readme
源码仓库：https://github.com/Aaronius/penpal

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：132 kB，66 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：0 个
- 首次发布：2022-09-30T17:07:38.821Z
- 最新版本发布：2025-01-27T21:45:45.915Z
- 近 30 天下载量：41921（2026-10-09 至 2026-11-07，npm 官方下载统计）
- 已发布版本数：3（近 12 个月 0 个）

## 中文简介

一个基于承诺的图书馆,通过Message后与iframes通信.

## 安装

```sh
npm install @cartridge/penpal
```

也可以使用：`pnpm add @cartridge/penpal`、`yarn add @cartridge/penpal`、`bun add @cartridge/penpal`

## README

[![npm version](https://badge.fury.io/js/penpal.svg)](https://badge.fury.io/js/penpal)

### 从第五版升级? 见 [第6版发布注释](https://github.com/Aaronius/penpal/releases/tag/v6.0.0) 详细情况.

[见文件5.x](https://github.com/Aaronius/penpal/tree/5.x)  
[见4.x的文件](https://github.com/Aaronius/penpal/tree/4.x)  
[见3.x的文件](https://github.com/Aaronius/penpal/tree/3.x)

# 彭帕尔

Penpal是一个基于承诺的图书馆,通过后Message安全地与iframes通信. 母窗口可以调用被 Iframes 曝光的方法,通过参数,并收到返回值. 同样地,iframes可以调用被母窗口曝光的方法,传递参数,并获得回取值. 轻松点.

这个库没有依赖关系.

## 安装

### 使用 npm

最好能从npm开始用Penpal 和像捆绑机一样的 [网络软件包](https://webpack.github.io/), (中文(简体) ), [滚动](https://rollupjs.org/),或 [括号](https://parceljs.org/)。如果使用 npm 来管理客户端软件包,则可以安装 Penpal ,其中:

`npm install penpal`

### 使用 CDN 软件

如果您不想使用 npm 来管理客户端软件包, Penpal 也在 a 中提供 UMD 分布 `dist` 在 CDN 上托管的文件夹 :

`<script src="https://unpkg.com/penpal@^6/dist/penpal.min.js"></script>`

Penpal 将安装在 `window.Penpal`。 。 。 . `window.Penpal` 将包含下列属性:

```
Penpal.connectToChild
Penpal.connectToParent
Penpal.ErrorCode.ConnectionDestroyed
Penpal.ErrorCode.ConnectionTimeout
Penpal.ErrorCode.NoIframeSrc
```

使用方法与使用捆绑器类似,下面对此有记载,但您不会导入每个模块,而是会在 `Penpal` 改为全球.

## 使用量

### 父窗口

```javascript
import { connectToChild } from 'penpal';

const iframe = document.createElement('iframe');
iframe.src = 'http://example.com/iframe.html';

// This conditional is not Penpal-specific. It's merely
// an example of how you can add an iframe to the document.
if (
  document.readyState === 'complete' ||
  document.readyState === 'interactive'
) {
  document.body.appendChild(iframe);
} else {
  document.addEventListener('DOMContentLoaded', () => {
    document.body.appendChild(iframe);
  });
}

// This is where the magic begins.
const connection = connectToChild({
  // The iframe to which a connection should be made.
  iframe,
  // Methods the parent is exposing to the child.
  methods: {
    add(num1, num2) {
      return num1 + num2;
    },
  },
});

connection.promise.then((child) => {
  child.multiply(2, 6).then((total) => console.log(total));
  child.divide(12, 4).then((total) => console.log(total));
});
```

### 儿童框架

```javascript
import { connectToParent } from 'penpal';

const connection = connectToParent({
  // Methods child is exposing to parent.
  methods: {
    multiply(num1, num2) {
      return num1 * num2;
    },
    divide(num1, num2) {
      // Return a promise if the value being
      // returned requires asynchronous processing.
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(num1 / num2);
        }, 1000);
      });
    },
  },
});

connection.promise.then((parent) => {
  parent.add(3, 1).then((total) => console.log(total));
});
```

## API 密码

### `connectToChild(options: Object) => Object`

**Penpal 要正确操作, 你必须保证 `connectToChild` 在iframe呼叫前叫着 `connectToParent`。 。 。 .** 如以上例子所示,设置 `src` 或者说 `srcdoc` iframe 属性,并在调用 `connectToChild` 只要它们都在同一处 [Java 脚本事件循环](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop)。或者,您总是可以在文档中附加框架 _之后_ 电话 `connectToChild` 改为 _在此之前_。 。 。 .

#### 选项

`options.iframe: HTMLIFrameElement` (必须)

Penpal 应当连接的 Iframe 元素 。 除非你提供 `childOrigin` 选项,您需要设置 `src` 或者说 `srcdoc` iframe 呼叫前的财产 `connectToChild` 这样Penpal就可以自动获得孩子的血统. 除了普通的URL外, [数据 URIs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) 财务报告和审定财务报表 [文件 URIs](https://en.wikipedia.org/wiki/File_URI_scheme) 也得到支持.

`options.methods: Object` (可选)

含有儿童iframe调用方法的物体。 对象的键是方法名,值是函数. 带有函数值的嵌入对象被递归包含. 如果一个函数需要同步处理来确定其返回值,则使函数立即返回一个承诺,并在确定值后解决承诺.

`options.childOrigin: string` (可选)

在绝大多数情况下,Penpal可以自动根据儿童出生情况确定儿童出身 `src` 或者说 `srcdoc` 设置在 iframe 上的属性。 通信将自动限于这一来源.

在一些罕见的情况下,特别是在使用 `file://` 在各种设备上的协议,浏览器在如何报告和处理来源上不一致. 如果您收到一个错误, 表示父母收到来自意外来源的握手, 您可能需要使用此选项手动传递孩子来源 .

其他情况 [特殊情景](https://github.com/Aaronius/penpal/issues/73),您可能希望父母能够与任何儿童血统进行沟通。 在这种情况下,你可以设置 `childOrigin` 改为 `*`。 。 。 . **这是令人沮丧的.** 为了说明这种风险,如果一个邪恶的攻击者设法在孩子的页面内创建一个链接,让另一个用户可以点击(例如,如果你未能在信件板注释中不适当地逃脱 HTML),并且这个链接会引导不可疑的用户的iframe到邪恶的URL,那么邪恶的URL的页面就可以开始与你的母窗口通信.

无论你如何配置 `childOrigin`,通信将始终被限制在 iframe 中您正在连接.

`options.timeout: number` (可选)

时间之多,以毫秒计,彭帕勒应等孩子回应后再拒绝连接承诺. 默认没有超时.

`options.debug: boolean` (可选)

启用或禁用调试日志 。 除错日志默认已禁用 .

#### 返回值

返回值为 `connectToChild` 是一个 `connection` 具有下列属性的对象:

`connection.promise: Promise`

承诺一旦达成就会实现 承诺将用一个包含儿童暴露的方法的物体来解决。 注意,这些并不是关于孩子所接触的方法的实际记忆参考,而是彭帕勒用相同的名字和签名创建的代理方法. 当其中一种方法被调用时,彭帕勒会立即返回一个承诺,然后去工作,向孩子发送一个信息,用你通过的论点调用孩子内部的实际方法,然后将返回值寄回给父母. 你得到的允诺将按回报值解决.

`connection.destroy: Function`

一种在调用时会断开任何消息通道的方法. 在连接建立之前,您也可以拨打这个电话.

### `connectToParent([options: Object]) => Object`

#### 选项

`options.parentOrigin: string | RegExp` (可选) **但建议很高!**(中文(简体) )

您的 iframe 将与之通信的父窗口的来源 。 如果不提供,通信将不局限于任何特定的父来源,从而导致任何网页能够将您的网页装入iframe并与它通信.

`options.methods: Object` (可选)

包含用于母窗口调用的方法的对象 。 对象的键是方法名,值是函数. 带有函数值的嵌入对象被递归包含. 如果一个函数需要同步处理来确定其返回值,则使函数立即返回一个承诺,并在确定值后解决承诺.

`options.timeout: number` (可选)

时间量,以毫秒计,Penpal应等父母回复后再拒绝连接承诺. 默认没有超时.

`options.debug: boolean` (可选)

启用或禁用调试日志 。 除错日志默认已禁用 .

#### 返回值

返回值为 `connectToParent` 是一个 `connection` 具有下列属性的对象:

`connection.promise: Promise`

承诺一旦达成就会实现 承诺将通过包含父母曝光的方法的对象解决。 注意,这些并非对母体所暴露的方法的实际内存参考,而是彭帕勒用同名和签名创建的代理方法. 当其中一种方法被调用时,彭帕尔会立即返回一个承诺,然后去工作,向父母发送一个信息,用您通过的论点调用父母内部的实际方法,然后将返回值发送给孩子. 你得到的允诺将按回报值解决.

`connection.destroy: Function`

一种在调用时会断开任何消息通道的方法. 在连接建立之前,您也可以拨打这个电话.

## 重新连接

如果孩子iframe试图与父母重新连接,父母会接受新的连接. 例如,如果用户将孩子的iframe刷新或浏览到另一个同样使用Penpal的页面,就可能出现这种情况. 在这种情况下 `child` 对象,在初始连接建立时,父母会根据孩子iframe提供的新方法更新.

注:目前没有API通知消费者重新连接。 如果这对您很重要,请提供反馈 [这个问题](https://github.com/Aaronius/penpal/issues/58) 以及你希望看到 API 设计.

## 错误

Penpal会在某些情况下抛出(或拒绝承诺)错误。 每个错误都会有一个 `code` 属性,可用于程序决策(例如,如果错误是由于连接时断时而发生)以及 `message` 描述问题。 下列代码可能会出错 :

`ConnectionDestroyed`

当尝试调用方法时, 此错误会被抛出 `child` 或者说 `parent` 对象和连接先前已被销毁.

`ConnectionTimeout`

承诺在 `connection.promise` 会在 `timeout` 期限已过,尚未建立联系.

`NoIframeSrc`

当 iframe 传递到 `connectToChild` 没有 `src` 或者说 `srcdoc` 设置.

为了方便,这些错误代码可以导入如下:

```
import { ErrorCode } from 'penpal';
// ErrorCode.ConnectionDestroyed
// ErrorCode.ConnectionTimeout
// ErrorCode.NoIframeSrc
```

## 类型脚本

打电话时 `connectToChild` 或者说 `connectToParent`,您可以通过一个通用类型的参数。 这将用于键入 `child` 或者说 `parent` 对象 `connection.promise` 解决了。 这一点在代码中得到更好的解释:

```typescript
import { connectToChild } from 'penpal';

// This interace could be imported from a code library
// that both the parent and child share.
interface ChildApi {
  multiply(...args: number[]): number;
}

// Supply the interface as a generic argument.
const connection = connectToChild<ChildApi>({
  iframe: new HTMLIFrameElement(),
});

// The resulting child object will contain properly
// typed methods.
const child = await connection.promise;
// The result variable is typed as a number.
const result = await child.multiply(1, 3);
```

下列类型也会导出为您使用的命名常数 :

-   `Connection`
-   `Methods`
-   `AsyncMethodReturns`
-   `CallSender`
-   `PenpalError`

## 反应

如果你在React应用软件中使用了Penpal 请检查一下 [@weblivion/react-penpal](https://www.npmjs.com/package/@weblivion/react-penpal)。 。 。 .

## 支持的浏览器

Penpal被设计成功运行在Chrome,Firefox,Safari,和Edge等最新版本上. 如果您需要支持Internet Explorer 11,请随意使用Penpal的3.x版本. 见 [3.x 读取](https://github.com/Aaronius/penpal/tree/3.x) 用于文档.

据报道,Penpal还在iOS和Android装置的Ionic项目内工作.

## 灵感

这个图书馆的灵感来自:

-   [输出](https://github.com/dollarshaveclub/postmate)
-   [JSCANNEL 语言](https://github.com/mozilla/jschannel)

## 许可证

麻省理工学院

## 常见问题

### @cartridge/penpal 是什么？

一个基于承诺的图书馆,通过Message后与iframes通信\.

### 如何安装 @cartridge/penpal？

在项目目录运行 npm install @cartridge/penpal，或使用 pnpm add / yarn add / bun add。

### @cartridge/penpal 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @cartridge/penpal 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @cartridge/penpal 可以商用吗？

@cartridge/penpal 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @cartridge/penpal 的下载量有多少？

根据 npm 官方下载统计，@cartridge/penpal 在 2026/10/09 – 2026/11/07 这 30 天内被下载 41,921 次，日均约 1,397 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @cartridge/penpal 还在维护吗？

最新版本 6\.2\.4 发布于 2025/01/28（1\.8 年前）；至今共发布 3 个版本，其中过去 12 个月发布了 0 个；首次发布于 2022/10/01。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

