---
title: 小程序运行机制 - 内存缓存
summary: "介绍小程序内存缓存机制，包括冷启动与热启动的区别、生命周期事件及缓存配置。"
tags: [小程序运行机制, 内存缓存, 冷启动与热启动, 页面生命周期管理]
questions:
  - 小程序的冷启动和热启动有什么区别？
  - onPause 和 onResume 生命周期事件在什么时候触发？
  - 小程序在什么情况下会被销毁？
  - 如何配置小程序退出时保留页面堆栈？
  - 如何主动禁用小程序的内存缓存？
  - 哪些场景下小程序不会被内存缓存？
  - 如何在函数组件中监听内存缓存相关的生命周期事件？
  - 小程序进入后台后多久会被销毁？
  - 热启动时小程序打开的页面规则是什么？
  - cachePageStack 和 disableCache 配置项有什么作用？
---

## 内存缓存生命周期说明

为便于更清晰地感知小程序进入与恢复内存缓存的状态变化，小程序 **App 对象** 上新增内存缓存相关生命周期事件，用于区分不同阶段并处理不同逻辑。

### 新增生命周期事件

| 事件名称 | 事件标识   | 触发时机                       |
| -------- | ---------- | ------------------------------ |
| 暂停     | `onPause`  | 小程序进入内存缓存状态时触发   |
| 恢复     | `onResume` | 小程序从内存缓存状态恢复时触发 |

### 兼容性说明

为保证现有小程序不受影响，原有的 `App.onShow` 与 `App.onHide` 生命周期仍会正常触发。

在涉及内存缓存的场景下，生命周期事件的触发顺序如下：

#### 进入内存缓存

1. 触发 `App.onPause`
2. 触发 `App.onHide`

#### 从内存缓存状态恢复

1. 触发 `App.onResume`
2. 触发 `App.onShow`

```js
export default class App extends React.Component {
  // did mount 的触发时机是在 onLaunch 的时候
  componentDidMount() {
    console.log('App launch');
  }
  onPause() {
    console.log('进入内存缓存状态');
  }
  onResume() {
    console.log('从内存缓存状态恢复')
  }
  render() {
    return this.props.children;
  }
}
```

对于函数组件的 App, 可以通过 useAppEvent hook 来监听生命周期

- ray 版本需 `>= 1.7.39`

```js
import { useAppEvent } from '@ray-js/ray';

export default function App(props) {
  useAppEvent('onPause', () => {
    console.log('进入内存缓存状态');
  });
  useAppEvent('onResume', () => {
    console.log('从内存缓存状态恢复')
  });
  return props.children;
}
```

## 1. 小程序生命周期

小程序从启动到最终销毁，会经历多个不同的状态，在不同状态下有不同的运行表现。  
整体流程如下图所示：

<Image src='/images/guide/memoryCache.png' />

### 1.1 小程序启动

从用户的角度来看，小程序的启动可以分为两种：

- **冷启动**：  
  当用户第一次打开小程序，或者小程序被销毁后再次打开时，需要重新加载全部资源并启动，这种情况称为冷启动。

- **热启动**：  
  当用户之前已经打开过小程序，在短时间内再次进入时，小程序并未销毁，只是从后台恢复到前台，这称为热启动。

> 在生命周期术语中，我们通常将“启动”特指冷启动，而热启动一般描述为「后台切前台」。

### 1.2 前台与后台

当小程序启动后并展示给用户时，处于「**前台**」状态。  
用户离开小程序时，小程序并不会立即销毁，而是进入「**后台**」状态，此时仍会短暂保留在内存中。

**进入后台的常见方式包括：**

- 点击右上角胶囊按钮离开小程序
- iOS 从屏幕左侧右滑返回
- Android 点击返回键
- 小程序运行时切后台（Home 键或手势）
- 小程序运行时锁屏

当用户再次回到 App 并打开该小程序，小程序会重新进入「前台」状态。

### 1.3 小程序销毁

当小程序长时间未被使用或系统资源不足时，小程序会被彻底销毁。  
销毁后，再次打开即为冷启动。

**常见销毁场景包括：**

- 小程序进入后台后 10 分钟未重新进入前台；
- 同时打开超过三个小程序时，最早进入后台的小程序会被销毁。

---

## 2. 小程序冷启动的页面

当小程序冷启动时，打开的页面有以下情况：

- **A 类场景**：启动场景中不带 path，小程序容器会根据 `entryPagePath` 进入默认页面。
- **B 类场景**：启动场景中带有 path，小程序将直接进入对应页面。

---

## 3. 小程序热启动的页面

热启动时，小程序打开的页面规则如下：

- 默认情况下，热启动会回到小程序冷启动时进入的第一个页面；
- 若配置了 `cachePageStack: true`，则会**保留上次的浏览状态**，即恢复上次退出前的页面堆栈。

> 配置项位置：`global.config.ts`

| **属性**       | **类型** | **必填** | **描述**               |
| -------------- | -------- | -------- | ---------------------- |
| cachePageStack | boolean  | 否       | 退出时是否保留所有页面 |

---

## 4. 主动销毁

如果业务上希望小程序每次启动都重新加载，可以通过如下配置项实现主动销毁：

> 配置项位置：`global.config.ts`

| **属性**     | **类型** | **必填** | **描述**             |
| ------------ | -------- | -------- | -------------------- |
| disableCache | boolean  | 否       | 退出时是否销毁小程序 |

当配置为 `true` 时，小程序生命周期如下图所示：

<Image src='/images/guide/noMemoryCache.png' />

---

## 5. 不进行内存缓存的场景说明

在某些情况下，小程序关闭时会**直接销毁**，而不会进行内存缓存。  
也就是说，下次打开时会重新加载，而非从内存中恢复。

以下情况会触发直接关闭（不缓存）：

- **非正式版本的小程序**：
  如开发版、体验版等不做缓存。

- **关闭时有白屏**：
  若用户关闭时小程序页面异常（如白屏），系统会直接销毁，避免恢复异常页面。

- **关闭时小程序流程未结束**：
  比如仍有小程序启动流程、接口请求在执行中，此时不会缓存。

- **小程序主动禁用缓存**：
  若在`global.config.ts`配置中设置了 `disableCache: true`，关闭后直接销毁。

- **开启了体验评分功能的小程序**：
  当用户可对小程序进行体验评分时，为保证体感一致性，不使用缓存。

- **处于原生 Tab 栏的小程序**：
  在 Native Tab 栏中的小程序不支持内存缓存，会直接关闭。

---

## 6. 补充说明

- 只有在满足缓存条件的情况下，小程序关闭时才会进入内存缓存状态
- 被缓存的小程序在再次打开时，可更快恢复到上次状态，提升体验
- 若不满足缓存条件或被主动销毁，下次打开小程序即为冷启动

## 7. 常见问题（FAQ）

### Q1：为什么我点击手机的返回键退出小程序后，再次进入时还停留在上次页面？

这是因为当前小程序在关闭时被**内存缓存**了。  
当你再次打开时，系统会直接恢复上次的状态，而不是重新启动。

**解决方法：**
在小程序的全局配置文件 `global.config.ts` 中设置：

```ts
   disableCache: true
```

### Q2：我想保留小程序上次操作的页面，下次打开还能接着用，要怎么配置？

只需确保：

- 没有设置`disableCache: true`
- 没有触发直接关闭的情况（见上文第5节）

默认情况下，小程序会自动进入内存缓存模式，下次打开会恢复到上次界面。

### Q3: 哪些情况下小程序不会被缓存？

- 小程序是开发版/体验版
- 关闭时出现白屏
- 启动时后台任务未完成
- 启用了体验评分功能
- 在 Native Tab 栏中
- 显示配置了 `disableCache: true`
