Parse JavaScript 官方指南 · 详细教程(中文)

34次阅读
没有评论

共计 10623 个字符,预计需要花费 27 分钟才能阅读完成。


目录

  1. 快速认识 Parse
  2. 安装与引入(NPM / CDN / ESM / CJS)
  3. 初始化与环境区分(Browser / Node / React / Next.js)
  4. 基础概念(Class、Object、Pointer、Relation、CLP、ACL、Role、Session)
  5. 数据读写(CRUD)
  6. 查询(Query)详解:条件、排序、分页、组合、聚合、distinct
  7. 关系建模与关联查询
  8. 用户体系与认证(注册 / 登录 / 匿名 / 第三方)
  9. 权限与安全(CLP、ACL、Pointer Permissions、useMasterKey、Session Token)
  10. 文件与图片(Parse.File)
  11. Cloud Code(云函数 / 触发器 / 定时任务)
  12. 实时功能(LiveQuery)
  13. 批量操作与数据迁移
  14. TypeScript 最佳实践
  15. 在 React / Next.js / Node 中使用
  16. 错误处理与调试
  17. 性能优化与运维建议
  18. 常见坑与 FAQ
  19. 速查清单(Cheat Sheet)
  20. 最小可运行示例(拷贝即用)

1. 快速认识 Parse

Parse 是一个开源 BaaS(Backend as a Service)方案:搭配 Parse Server 与多端 SDK(含 JS)即可快速获得数据存储、用户认证、文件存储、云函数、实时订阅等能力。你可以:

  • 自建 Parse Server(Node.js + MongoDB/Postgres)
  • 或使用托管服务(例如 Back4App 等)

为什么选 Parse JS?

  • 一套 SDK 覆盖浏览器、Node.js、React Native。
  • 无需从零写大量增删改查与会话管理代码。
  • 既能“无后端”快速起步,也能通过 Cloud Code 编写严谨的后端逻辑。

2. 安装与引入(NPM / CDN / ESM / CJS)

2.1 通过 NPM / Yarn / pnpm

npm install parse
# 或
yarn add parse
# 或
pnpm add parse

2.2 浏览器直接引入(CDN)

<script src="https://unpkg.com/parse/dist/parse.min.js"></script>

此时全局可用 Parse 对象。

2.3 ESM / CJS 导入

// ESM(Node、构建型前端)import Parse from 'parse/dist/parse.min.js';
// 或在 Node 端:import Parse from 'parse/node.js';

// CommonJS(老项目)const Parse = require('parse/node');

提示:在 Node 环境优先使用 parse/node 入口,以获得合适的适配(如没有 window 的环境)。


3. 初始化与环境区分

3.1 浏览器(自建 Parse Server)

<script src="https://unpkg.com/parse/dist/parse.min.js"></script>
<script>
  Parse.initialize('YOUR_APP_ID');
  Parse.serverURL = 'https://your-parse-server.example.com/parse';

  // 如果使用托管,通常还会提供 JavaScript Key:// Parse.initialize('APP_ID', 'JAVASCRIPT_KEY');
  // Parse.serverURL = 'https://parseapi.back4app.com/';

  // 可选:LiveQuery(如启用)// Parse.liveQueryServerURL = 'wss://your-parse-server.example.com/';
</script>

3.2 Node.js(服务端脚本 /SSR)

import Parse from 'parse/node.js';

Parse.initialize('YOUR_APP_ID');
Parse.serverURL = 'https://your-parse-server.example.com/parse';
// 若在服务端使用 masterKey(谨慎):// Parse.masterKey = 'YOUR_MASTER_KEY';

安全提示 masterKey 只应出现在受控的服务端环境, 不要 在浏览器或移动端泄露。

3.3 环境区分与多配置

为 dev/staging/prod 分别设置 APP_IDserverURLliveQueryServerURL,并使用环境变量注入构建:

Parse.initialize(import.meta.env.VITE_PARSE_APP_ID);
Parse.serverURL = import.meta.env.VITE_PARSE_SERVER_URL;

3.4 在 Next.js 中

  • 仅在客户端初始化(比如在 useEffect 内或 pages/_app.tsxuseEffect),避免 SSR 时访问 window
  • 或在 API Routes 中使用 parse/nodemasterKey 执行受信逻辑。

4. 基础概念

  • Class:类似数据库中的表,例如 BookAuthor
  • Object:表中的一行(Parse.Object),有 objectIdcreatedAtupdatedAt
  • Pointer:外键指针(对象引用),实现一对多 / 多对一。
  • Relation:多对多关系(relation('members'))。
  • Query:查询构造器(筛选、排序、分页、include 等)。
  • User / Role / Session:用户、角色与会话管理。
  • CLP(Class Level Permissions):表级权限设置(create/read/update/delete/find 等)。
  • ACL(Access Control List):对象级权限(指定某用户 / 角色可读 / 写)。
  • Pointer Permissions:基于字段的细粒度访问控制(如“作者只能改自己文章”)。

5. 数据读写(CRUD)

5.1 新建与保存

const Book = Parse.Object.extend('Book');
const book = new Book();
book.set('title', 'Clean Code');
book.set('price', 88);
await book.save();

5.2 读取单条 / 更新 / 删除

// 读取单条
const query = new Parse.Query('Book');
const one = await query.get('OBJECT_ID');

// 更新
one.set('price', 99);
await one.save();

// 删除
await one.destroy();

5.3 批量保存 / 删除

const a = new Parse.Object('Book').set('title', 'A');
const b = new Parse.Object('Book').set('title', 'B');
await Parse.Object.saveAll([a, b]);
// 批量删除:await Parse.Object.destroyAll([a, b]);

6. 查询(Query)详解

6.1 常见条件

const q = new Parse.Query('Book');
q.equalTo('title', 'Clean Code');
q.notEqualTo('status', 'archived');
q.greaterThan('price', 50);
q.greaterThanOrEqualTo('stock', 1);
q.lessThan('price', 200);
q.containedIn('category', ['tech', 'design']);
q.matches('title', /^Clean/i);   // 正则

6.2 结果控制

q.select(['title', 'price']);      // 只取部分字段
q.include('author');               // 预取指针对象
q.ascending('price');              // 排序
q.limit(20).skip(0);               // 分页
const rows = await q.find();

6.3 组合查询

// OR
const q1 = new Parse.Query('Book').lessThan('price', 50);
const q2 = new Parse.Query('Book').equalTo('isOnSale', true);
const or = Parse.Query.or(q1, q2);
const list = await or.find();

// AND(两种做法)// ① 单个查询上叠加多个条件(常用)// ② 或使用 Parse.Query.and(qA, qB) 组合两个查询

6.4 关联匹配

// 子查询:找出作者在“VIP”组内的书
const vipAuthorQ = new Parse.Query('Author').equalTo('isVIP', true);
const bookQ = new Parse.Query('Book');
bookQ.matchesQuery('author', vipAuthorQ);
const vipBooks = await bookQ.find();

6.5 聚合与 distinct(高级)

// distinct(去重某字段值)const q = new Parse.Query('Book');
const categories = await q.distinct('category');

// aggregate(MongoDB 聚合管道)const pipeline = [
  {$match: { price: { $gte: 50} } },
  {$group: { _id: '$category', avgPrice: { $avg: '$price'} } },
  {$sort: { avgPrice: -1} }
];
const stats = await q.aggregate(pipeline);

注意:聚合能力依赖后端数据库与 Parse Server 版本,生产前先在测试库验证。


7. 关系建模与关联查询

7.1 Pointer(指针,一对多 / 多对一)

const author = await new Parse.Object('Author').set('name', 'Bob').save();
const book = new Parse.Object('Book');
book.set('title', 'Patterns');
book.set('author', author); // Pointer
await book.save();

7.2 Relation(多对多)

const group = await new Parse.Object('Group').save();
const rel = group.relation('members');
rel.add([user1, user2]);
await group.save();

7.3 include 与反向查询

// include 预加载指针,避免 N+1
const q = new Parse.Query('Book');
q.include('author');
const list = await q.find();

// 反向:找出某作者的所有书
const q2 = new Parse.Query('Book').equalTo('author', author);
const booksOfAuthor = await q2.find();

8. 用户体系与认证

8.1 注册 / 登录 / 登出

// 注册
const user = new Parse.User();
user.set('username', 'alice');
user.set('password', 's3cret');
user.set('email', 'a@b.com');
await user.signUp();

// 登录
const logged = await Parse.User.logIn('alice', 's3cret');

// 当前用户(前端环境)const current = Parse.User.current();

// 登出
await Parse.User.logOut();

8.2 匿名登录 / 第三方登录(思路)

  • 匿名登录:在 Parse Server 端启用 Anonymous Provider,客户端可创建匿名用户,后续可“合并 / 绑定”到正式账号。
  • 第三方:自定义 Auth Provider,在 Cloud Code/Server 校验第三方 token,客户端用 linkWith/logInWith 完成绑定或登录。

8.3 密码重置与邮箱验证

  • 在 Server 端开启相应邮件配置(SMTP),即可使用 Parse.User.requestPasswordReset(email) 等能力。

9. 权限与安全

9.1 CLP(Class Level Permissions)

  • 控制某个 Class 是否允许 find / get / create / update / delete
  • 生产环境常见策略:关闭匿名写入,只允许已登录用户读取部分表,敏感表仅允许角色写入。

9.2 ACL(对象级权限)

const post = new Parse.Object('Post');
post.set('title', 'Hello');

const acl = new Parse.ACL();
acl.setPublicReadAccess(true);      // 公开可读
acl.setWriteAccess(Parse.User.current(), true); // 仅作者可写
post.setACL(acl);
await post.save();

9.3 Pointer Permissions(基于字段)

  • 例如让 Post.author 指向的用户拥有写权限,可通过指针权限配置达成。

9.4 useMasterKey 与 Session Token

  • 在 Cloud Code 或可信服务端,可使用 useMasterKey: true 绕过 CLP/ACL(务必谨慎)。
  • 在云函数中基于 request.user + request.installationId 做鉴权;若要代表某用户操作,可接受其 sessionToken

10. 文件与图片(Parse.File)

// base64 上传
const file = new Parse.File('avatar.png', { base64: base64Data});
await file.save();

// 绑定到对象
const profile = new Parse.Object('Profile');
profile.set('avatar', file);
await profile.save();

// 读取 URL
const url = file.url();

存储位置由 Parse Server 配置决定(本地、S3、GCS 等)。


11. Cloud Code(云函数 / 触发器 /Job)

11.1 云函数定义与调用

cloud/main.js

Parse.Cloud.define('sum', async (req) => {const { a, b} = req.params;
  if (typeof a !== 'number' || typeof b !== 'number') throw 'Invalid params';
  return a + b;
});

客户端调用

const result = await Parse.Cloud.run('sum', { a: 1, b: 2});

11.2 触发器(校验 / 审计)

Parse.Cloud.beforeSave('Book', async (req) => {
  const book = req.object;
  if (book.get('price') < 0) throw 'price must be >= 0';
});

11.3 定时任务(Job)

Parse.Cloud.job('rebuildStats', async (req) => {// 周期性汇总统计、清理数据、发送报表等});

12. 实时功能(LiveQuery)

12.1 客户端订阅

const q = new Parse.Query('Message');
q.equalTo('roomId', 'r1');

const sub = await q.subscribe();
sub.on('create', obj => console.log('new:', obj.toJSON()));
sub.on('update', obj => console.log('upd:', obj.toJSON()));
sub.on('delete', obj => console.log('del:', obj.id));

12.2 服务端配置要点

  • 启动 LiveQuery Server 并配置 classNames 白名单。
  • 前端设置 Parse.liveQueryServerURL = 'wss://...'
  • 注意心跳 / 断线重连策略。

13. 批量操作与数据迁移

  • Parse.Object.saveAll([...])Parse.Object.destroyAll([...])
  • 导入导出:可写脚本在 Node 环境读写 JSON/CSV 并调用 SDK。
  • 对历史大表的结构调整,建议:影子表 / 双写、灰度迁移、后台 Job + 进度日志。

14. TypeScript 最佳实践

14.1 为对象建类型

// 定义字段接口
interface BookAttrs {
  title: string;
  price: number;
  author?: Parse.Pointer; // 或具体类型
}

// 泛型扩展 Parse.Object
class Book extends Parse.Object<BookAttrs> {constructor() {super('Book'); }
  get title() { return this.get('title'); }
  set title(v: string) {this.set('title', v); }
}
Parse.Object.registerSubclass('Book', Book);

14.2 API 类型提示

  • 直接安装 parse 包即可获得类型声明。
  • 对复杂聚合结果定义专用接口增强可读性。

15. 在 React / Next.js / Node 中使用

15.1 React(前端)

import {useEffect, useState} from 'react';
import Parse from 'parse/dist/parse.min.js';

export default function BookList() {const [books, setBooks] = useState([]);

  useEffect(() => {Parse.initialize(import.meta.env.VITE_APP_ID);
    Parse.serverURL = import.meta.env.VITE_SERVER_URL;
    (async () => {const q = new Parse.Query('Book');
      q.limit(20);
      const rows = await q.find();
      setBooks(rows.map(r => r.toJSON()));
    })();}, []);

  return (
    <ul>
      {books.map(b => (<li key={b.objectId}>{b.title} - {b.price}</li>
      ))}
    </ul>
  );
}

15.2 Next.js(避免 SSR 触发)

  • 在客户端组件或 useEffect 中初始化 SDK。
  • 若需服务端读写,使用 API Route + parse/node,并在服务端读取机密(如 masterKey)。

15.3 Node 脚本(任务 / 迁移)

import Parse from 'parse/node.js';
Parse.initialize(process.env.APP_ID);
Parse.serverURL = process.env.SERVER_URL;
Parse.masterKey = process.env.MASTER_KEY; // 受控环境

const main = async () => {const q = new Parse.Query('Book');
  q.greaterThan('price', 50);
  const rows = await q.find({useMasterKey: true});
  console.log('count:', rows.length);
};
main();

16. 错误处理与调试

16.1 常见错误

  • 认证类:用户名已存在、未验证邮箱、密码错误、会话过期。
  • 权限类:无权读取 / 写入(检查 CLP/ACL/Pointer Permissions)。
  • 查询类:缺索引导致超时、字段名拼写错误、误用正则导致慢查询。

16.2 处理方式

try {await someParseCall();
} catch (err) {
  // err.code / err.message(根据 SDK 版本)console.error(err);
}

16.3 调试建议

  • 打开 Parse Server 日志(请求、错误、慢查询)。
  • 在 Cloud Code 中为关键路径加日志;必要时引入 traceId。

17. 性能优化与运维建议

  • 权限先行:生产环境关闭匿名写,敏感表仅角色可写。
  • 最小化数据select 只取必需字段;include 仅包含必要指针。
  • 善用索引:对高频过滤字段建立索引;避免无索引正则前缀匹配。
  • 聚合分层:重统计走 Cloud Job 或预聚合;列表页返回轻量数据。
  • 缓存策略:Cloud Code 里可对热点数据做短期缓存(如内存 /Redis)。
  • 分环境:dev/staging/prod 独立 DB。
  • 备份与迁移:定期备份,迁移走影子表与灰度策略。

18. 常见坑与 FAQ

  1. 在 Cloud Code 用 Parse.User.current() 不要。使用 req.user(或 sessionToken)。
  2. 触发器没执行? 检查函数名、导出路径、是否返回 Promise/async、Server 日志。
  3. LiveQuery 收不到事件? 检查服务端 class 白名单、客户端 liveQueryServerURL、网络 / 心跳设置。
  4. 前端报无权访问? 复核 CLP/ACL/Pointer Permissions;本地用 useMasterKey 只是“测通”,生产请走正确权限链。
  5. Next.js SSR 报 window 未定义? 仅在客户端初始化 SDK;服务端请用 parse/node

19. 速查清单(Cheat Sheet)

// 初始化
Parse.initialize('APP_ID');
Parse.serverURL = 'https://your-server/parse';

// 新增
const o = new Parse.Object('Todo');
o.set('title', 'Learn Parse');
await o.save();

// 查询
const q = new Parse.Query('Todo');
q.equalTo('done', false);
q.limit(10).descending('createdAt');
const rows = await q.find();

// 用户
await new Parse.User({username: 'u', password: 'p'}).signUp();
await Parse.User.logIn('u', 'p');
await Parse.User.logOut();

// 文件
const f = new Parse.File('a.txt', { base64: b64});
await f.save();

// 云函数
const x = await Parse.Cloud.run('sum', { a:1, b:2});

// LiveQuery
const sub = await new Parse.Query('Msg').subscribe();
sub.on('create', m => console.log(m.toJSON()));

20. 最小可运行示例(浏览器)

将以下内容保存为 index.html,替换 APP_IDSERVER_URL 后直接打开:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Parse JS Quickstart</title>
  <script src="https://unpkg.com/parse/dist/parse.min.js"></script>
  <style>body{font-family:system-ui,Arial;padding:24px}input{margin:4px}</style>
</head>
<body>
  <h1>Parse JS Quickstart</h1>
  <p>
    <input id="username" placeholder="Username"/>
    <input id="email" type="email" placeholder="Email"/>
    <input id="password" type="password" placeholder="Password"/>
    <button id="signup">Sign Up</button>
  </p>
  <script>
    Parse.initialize('APP_ID');
    Parse.serverURL = 'https://your-parse-server.example.com/parse';

    document.getElementById('signup').addEventListener('click', async () => {const u = new Parse.User();
      u.set('username', document.getElementById('username').value);
      u.set('email', document.getElementById('email').value);
      u.set('password', document.getElementById('password').value);
      try {await u.signUp();
        alert('Sign up success:' + u.id);
      } catch (e) {alert('Error:' + e.message);
      }
    });
  </script>
</body>
</html>

正文完
 0
一诺
版权声明:本站原创文章,由 一诺 于2025-10-10发表,共计10623字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码