跳至内容

Meteor API

Meteor 全局对象包含许多用于处理实用程序、网络等的函数和属性。

核心 API

Meteor.startup

摘要

在客户端或服务器启动时运行代码。

参数

源代码
名称类型描述必需
func函数

启动时要运行的函数。

在服务器上,该函数将在服务器进程完成启动后立即运行。在客户端上,该函数将在 DOM 准备好后立即运行。包装在 Meteor.startup 中的代码始终在所有应用程序文件加载后运行,因此如果您想访问其他文件中的共享变量,则应在此处放置代码。

startup 回调按调用 Meteor.startup 的顺序调用。

在客户端上,来自包的 startup 回调将首先被调用,然后是 <body> 模板来自您的 .html 文件,然后是您的应用程序代码。

js
import { Meteor } from "meteor/meteor";
import { LinksCollection } from "/imports/api/links";

Meteor.startup(async () => {
  // If the Links collection is empty, add some data.
  if ((await LinksCollection.find().countAsync()) === 0) {
    await LinksCollection.insertAsync({
      title: "Do the Tutorial",
      url: "https://www.meteor.js.cn/tutorials/react/creating-an-app",
    });
  }
});
js
import React from "react";
import { createRoot } from "react-dom/client";
import { Meteor } from "meteor/meteor";
import { App } from "/imports/ui/App";

// Setup react root
Meteor.startup(() => {
  const container = document.getElementById("react-target");
  const root = createRoot(container);
  root.render(<App />);
});

Meteor.promisify

摘要

获取一个具有回调参数作为最后一个参数的函数并将其变成 Promise。一种选择是使用节点实用程序 utils.promisify,但它在浏览器上不起作用。

参数

源代码
名称类型描述必需
fn函数----
context对象----
errorFirst布尔值

如果回调遵循 errorFirst 样式,则默认为 true

js
import { Meteor } from "meteor/meteor";

/** @returns function */
const result = Meteor.promisify();
  () => {},
context, // this param is optional

false, // this param is optional
);

Meteor.defer

摘要

延迟函数的执行以在后台异步运行(类似于 Meteor.setTimeout(func, 0)

参数

源代码
名称类型描述必需
func函数

要运行的函数

js
import { Meteor } from "meteor/meteor";


const result = Meteor.defer();
  () => {}
);

Meteor.absoluteUrl

摘要

生成指向应用程序的绝对 URL。服务器从 ROOT_URL 环境变量读取以确定它在哪里运行。对于部署到 Galaxy 的应用程序,这会自动处理,但在使用 meteor build 时必须提供。

参数

源代码
名称类型描述必需
path字符串

要附加到根 URL 的路径。不要包含前导“/”。

options对象

选项

名称类型描述必需
secure布尔值

创建 HTTPS URL。

replaceLocalhost布尔值

将 localhost 替换为 127.0.0.1。对于不识别 localhost 作为域名服务的很有用。

rootUrl字符串

覆盖服务器环境中的默认 ROOT_URL。例如:“http://foo.example.com

js
import { Meteor } from "meteor/meteor";


const result = Meteor.absoluteUrl();
  "path",  // this param is optional 
options, // this param is optional
);

Meteor.settings

摘要

Meteor.settings 包含特定于部署的配置选项。您可以通过传递 --settings 选项(它采用包含 JSON 数据的文件的名称)到 meteor runmeteor deploy 来初始化设置。当直接运行服务器(例如从捆绑包中)时,您改为通过将 JSON 直接放入 METEOR_SETTINGS 环境变量中来指定设置。如果设置对象包含一个名为 public 的键,则 Meteor.settings.public 将在客户端和服务器上可用。Meteor.settings 的所有其他属性仅在服务器上定义。即使没有指定设置,您也可以依赖 Meteor.settingsMeteor.settings.public 在客户端和服务器上都被定义为对象(而不是未定义)。运行时对 Meteor.settings.public 的更改将被新的客户端连接获取。

Meteor.release

摘要

Meteor.release 是一个字符串,包含项目构建时使用的 版本 的名称(例如,"1.2.3")。如果项目使用 Meteor 的 git 检出进行构建,则它为 undefined

Meteor.isClient

摘要

布尔变量。如果在客户端环境中运行,则为真。

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isClient) {
  // do something
}

Meteor.isServer

摘要

布尔变量。如果在服务器环境中运行,则为真。

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isServer) {
  // do something
}

危险

Meteor.isServer 可用于限制代码运行的位置,但它不会阻止代码发送到客户端。任何您不想提供给客户端的敏感代码,例如包含密码或身份验证机制的代码,都应保存在 server 目录中。

Meteor.isCordova

摘要

布尔变量。如果在 Cordova 移动环境中运行,则为真。

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isCordova) {
  // do something
}

Meteor.isDevelopment

摘要

布尔变量。如果在开发环境中运行,则为真。

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isDevelopment) {
  // do something
}

Meteor.isProduction

摘要

布尔变量。如果在生产环境中运行,则为真。

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isProduction) {
  // do something
}

Meteor.isModern

摘要

布尔变量。如果在“现代”JS 环境中运行,则为真,由 modern 包确定。

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isModern) {
  // do something
}

Meteor.isTest

摘要

布尔变量。运行单元测试时为真(如果在完整应用程序模式下运行测试则为假)。

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isTest) {
  // do something
}

Meteor.isAppTest

摘要

布尔变量。如果针对您的应用程序运行测试,则为真,即 meteor test --full-app

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isAppTest) {
  // do something
}

Meteor.isPackageTest

摘要

布尔变量。如果针对 Meteor 包运行测试,则为真。

js
import { Meteor } from 'meteor/meteor';

/** @type {Boolean} */
if (Meteor.isPackageTest) {
  // do something
}

Meteor.gitCommitHash

摘要

十六进制 Git 提交哈希,如果应用程序使用 Git 进行版本控制。否则为未定义。

方法 API

Meteor 方法是远程过程调用 (RPC),是由 Meteor.methods 定义并由 Meteor.call 调用的函数。

Meteor.methods

摘要

定义可以由客户端通过网络调用的函数。

参数

源代码
名称类型描述必需
methods对象

键为方法名称、值为函数的字典。

定义方法的最基本方法是提供一个函数

js
import { Meteor } from "meteor/meteor";

Meteor.methods({
  sum(a, b) {
    return a + b;
  },
});
js
import { Meteor } from "meteor/meteor";

const result = await Meteor.callAsync("sum", 1, 2);
console.log(result); // 3

您可以使用 Meteor.methods 同时定义多个方法。

您可以将 Meteor.methods 视为定义服务器 API 的远程对象的一种方式。

一个更完整的示例

js
import { Meteor } from "meteor/meteor";
import { check } from "meteor/check";
import { LinksCollection } from "/imports/api/links";

Meteor.methods({
  async addLink(link) {
    check(link, String); // check if the link is a string

    // Do stuff...
    const linkID = await LinksCollection.insertAsync(link);
    if (/* you want to throw an error */) {
      throw new Meteor.Error('Something is wrong', "Some details");
    }

    return linkID;
  },

  bar() {
    // Do other stuff...
    return 'baz';
  }
});
js
import React from "react";
import { Meteor } from "meteor/meteor";

function Component() {
  const addLink = () =>
    Meteor.callAsync(
      "addLink",
      "https://www.meteor.js.cn/tutorials/react/creating-an-app"
    );

  return (
    <div>
      <button onClick={addLink}>Add Link</button>
    </div>
  );
}

在服务器上调用 methods 定义了可以由客户端远程调用的函数。它们应该返回一个 EJSON 可处理的值或抛出一个异常。在您的方法调用内部,this 绑定到一个方法调用对象,该对象提供以下内容

  • isSimulation:布尔值,如果此调用是存根,则为真。
  • unblock:调用时,允许来自此客户端的下一个方法开始运行。
  • userId:当前用户的 ID。
  • setUserId:将当前客户端与用户关联的函数。
  • connection:在服务器上,接收此方法调用的 连接

在客户端上调用 methods 定义与相同名称的服务器方法关联的存根函数。如果您不想,则不必为您的方法定义存根。在这种情况下,方法调用就像其他系统中的远程过程调用一样,您必须等待服务器的结果。

如果您确实定义了存根,当客户端调用服务器方法时,它也会并行运行其存根。在客户端上,存根的返回值被忽略。存根是为了其副作用而运行的:它们旨在模拟服务器方法将执行的操作的结果,但无需等待往返延迟。如果存根抛出异常,它将记录到控制台。

您始终使用方法,因为数据库变异器(insertupdateremove)是作为方法实现的。当您在客户端上调用这些函数中的任何一个时,您正在调用其更新本地缓存的存根版本,并将相同的写入请求发送到服务器。当服务器响应时,客户端使用服务器上实际发生的写入更新本地缓存。

您不必将所有方法定义都放入单个 Meteor.methods 调用中;您可以多次调用它,只要每个方法都有唯一的名称即可。

如果客户端调用一个方法并在收到响应之前断开连接,它将在重新连接时重新调用该方法。这意味着客户端可能多次调用一个方法,而实际上只需要调用一次。如果这种行为对您的方法造成问题,请考虑在客户端的每次方法调用中附加一个唯一的 ID,并在服务器上检查是否已经进行过具有此 ID 的调用。或者,您可以使用带有设置为 true 的 noRetry 选项的Meteor.apply

在 Meteor 指南的方法文章中了解更多关于方法及其使用方法的信息。

Meteor.isAsyncCall

摘要

判断方法调用是否来自 call 或 callAsync。

此方法可用于确定当前方法调用是否为异步调用。如果方法在服务器上运行并来自异步调用 (Meteor.callAsync),则返回 true。

js
import { Meteor } from "meteor/meteor";

Meteor.methods({
  async foo() {
    return Meteor.isAsyncCall();
  },
});
js
import { Meteor } from "meteor/meteor";

const result = await Meteor.callAsync("foo");
console.log(result); // true

Meteor.call("foo", (err, result) => {
  console.log(result); // false
});

this.userId

用户 ID 是一个任意字符串,通常是数据库中用户记录的 ID。您可以使用 setUserId 函数设置它。如果您使用的是Meteor 账户系统,则此操作将为您处理。

js
import { Meteor } from "meteor/meteor";

Meteor.methods({
  foo() {
    console.log(this.userId);
  },
});

this.setUserId

调用此函数以更改进行此方法调用的连接上当前登录的用户。这只是为在此连接上接收的未来方法调用设置 userId 的值。传递 null 以注销连接。

如果您使用的是内置的 Meteor 账户系统,则这应该对应于Meteor.users集合中文档的 _id 字段。

setUserId 不是追溯性的。它会影响当前方法调用和此连接上的任何未来方法调用。此连接上的任何先前方法调用仍然会看到它们开始时有效的 userId 值。

如果您还想更改客户端上的登录用户,则在服务器上调用 setUserId 后,在客户端上调用 Meteor.connection.setUserId(userId)

js
import { Meteor } from "meteor/meteor";

Meteor.methods({
  foo() {
    this.setUserId("some-id");
  },
});

this.connection

在方法调用内部访问。接收此方法的连接。如果方法与连接无关(例如,服务器发起的调用),则为 null。从服务器方法(该方法依次由客户端发起)发出的方法调用共享相同的连接。

Meteor.Error

摘要

此类表示方法抛出的符号错误。

参数

源代码
名称类型描述必需
error字符串

唯一标识此类错误的字符串代码。调用方法的客户端应使用此字符串来确定要采取的适当操作,而不是尝试解析 reason 或 details 字段。

出于向后兼容性的原因,某些内置的 Meteor 函数(例如 check)在此字段中抛出带有数字的错误。

reason字符串

可选。错误的简短人性化摘要,例如“未找到”。

details字符串

可选。有关错误的附加信息,例如文本堆栈跟踪。

js
import { Meteor } from "meteor/meteor"";

const error = new Meteor.Error();
  "error",
"reason", // this param is optional

"details", // this param is optional
);

例如

js
import { Meteor } from "meteor/meteor";
// on the server, pick a code unique to this error
// the reason field should be a useful debug message
Meteor.methods({
  methodName() {
    throw new Meteor.Error(
      "logged-out",
      "The user must be logged in to post a comment."
    );
  },
});
js
import { Meteor } from "meteor/meteor";
// on the client
Meteor.call("methodName", function (error) {
  // identify the error
  if (error && error.error === "logged-out") {
    // show a nice error message
    Session.set("errorMessage", "Please log in to post a comment.");
  }
});

如果您想从方法中返回错误,请抛出异常。方法可以抛出任何类型的异常。但是 Meteor.Error 是服务器将发送到客户端的唯一类型的错误。如果方法函数抛出其他异常,则它将在网络上映射到一个经过清理的版本。具体来说,如果抛出的错误上的 sanitizedError 字段设置为 Meteor.Error,则该错误将发送到客户端。否则,如果没有可用的清理版本,客户端将收到 Meteor.Error(500, 'Internal server error')

Meteor.call

摘要

使用同步存根调用方法,并传递任意数量的参数。

参数

源代码
名称类型描述必需
name字符串

要调用的方法名称

arg1, arg2...EJSONable

可选方法参数

asyncCallback函数

可选回调,在方法完成后异步调用,传递错误或结果。如果未提供,则方法将尽可能同步运行(见下文)。

这是使用同步存根调用方法的方法。它将在服务器上运行该方法。如果存在存根,它还将在客户端上运行存根。(另请参阅Meteor.apply,它与 Meteor.call 相同,只是您将参数指定为数组而不是作为单独的参数,并且您可以指定一些控制方法执行方式的选项。)

如果您将回调函数作为最后一个参数包含在内(它不能是方法的参数,因为函数不可序列化),则该方法将异步运行:它不会返回任何特定内容,也不会抛出异常。当方法完成时(这可能在 Meteor.call 返回之前或之后发生),回调将被调用,并带有两个参数:errorresult。如果抛出错误,则 error 将是异常对象。否则,error 将为 undefined,返回值(可能为 undefined)将在 result 中。

js
// Asynchronous call
Meteor.call('foo', 1, 2, (error, result) => { ... });

如果您在服务器上不传递回调,则方法调用将阻塞,直到方法完成。它最终将返回方法的返回值,或者如果方法抛出异常,则会抛出异常。(如果异常发生在远程并且不是 Meteor.Error 异常,则可能会映射到 500 服务器错误。)

js
// Synchronous call
const result = Meteor.call("foo", 1, 2);

在客户端,如果您不传递回调并且不在存根内部,call 将返回 undefined,并且您将无法获取方法的返回值。这是因为客户端没有 fiber,因此它实际上无法阻塞远程方法的执行。

最后,如果您在客户端的存根内部并调用另一个方法,则不会执行另一个方法(不会生成 RPC,不会发生任何“真实”的事情)。如果该其他方法具有存根,则该存根将替代该方法并执行。方法调用的返回值是存根函数的返回值。客户端在同步执行存根方面没有问题,这就是为什么客户端可以从方法体内部使用同步 Meteor.call 形式的原因,如前所述。

Meteor 跟踪客户端和服务器上方法执行的数据库写入,并且在服务器的所有写入替换本地缓存中的存根写入之前,不会调用 asyncCallback。在某些情况下,方法返回值可用与写入可见之间可能存在延迟:例如,如果另一个未完成的方法写入同一文档,则本地缓存可能要等到其他方法也完成之后才会更新。如果您希望在方法的结果从服务器到达后立即处理它,即使方法的写入尚未可用,也可以将 onResultReceived 回调指定给Meteor.apply

警告

仅当调用不具有存根或具有同步存根的方法时,才使用 Meteor.call。如果要调用具有异步存根的方法,可以使用 Meteor.callAsync 调用任何方法。

Meteor.callAsync

摘要

使用异步存根调用方法,并传递任意数量的参数。

参数

源代码
名称类型描述必需
name字符串

要调用的方法名称

arg1, arg2...EJSONable

可选方法参数

js
import { Meteor } from "meteor/meteor";

/** @returns Promise */
const result = Meteor.callAsync();
  "name",
{ num: 42 , someProp: "foo" }, // this param is optional
);

Meteor.callAsync 就像 Meteor.call 一样,只是它会返回一个 promise,您需要解决该 promise 才能获得结果。

Meteor.apply

摘要

调用方法并传递一个参数数组。

参数

源代码
名称类型描述必需
name字符串

要调用的方法名称

argsArray.<EJSONable>

方法参数

options对象
asyncCallback函数

可选回调;语义与Meteor.call中的相同。

选项

名称类型描述必需
wait布尔值

(仅限客户端)如果为 true,则不要发送此方法,直到所有先前的方法调用都已完成,并且在该方法完成之前不要发送任何后续方法调用。

onResultReceived函数

(仅限客户端)此回调在错误或结果可用时立即使用方法的错误或结果(就像 asyncCallback 一样)调用。本地缓存可能尚未反映方法执行的写入。

noRetry布尔值

(仅限客户端)如果为 true,则在重新加载时不要再次发送此方法,只需使用错误代码“invocation-failed”调用回调即可。

throwStubExceptions布尔值

(仅限客户端)如果为 true,则方法存根抛出的异常将被抛出而不是记录,并且不会在服务器上调用该方法。

returnStubValue布尔值

(仅限客户端)如果为 true,则在我们会丢弃存根的返回值并返回 undefined 的情况下,我们会继续返回它。具体来说,这是除以下情况之外的任何时候:(a)我们已经在存根内部或(b)我们在 Node 中并且没有提供回调。目前,我们要求显式传递此标志,以降低存根返回值与服务器返回值混淆的可能性;我们可能会在将来改进这一点。

js
import { Meteor } from "meteor/meteor";


const result = Meteor.apply();
  "name",
[{ num: 42 , someProp: "foo" }],
options, // this param is optional

() => {}, // this param is optional
);

Meteor.apply 就像 Meteor.call 一样,只是方法参数作为数组而不是直接作为参数传递,并且您可以指定有关客户端如何执行方法的选项。

警告

仅当调用不具有存根或具有同步存根的方法时,才使用 Meteor.apply。如果要调用具有异步存根的方法,可以使用 Meteor.applyAsync 调用任何方法。

Meteor.applyAsync

摘要

调用方法并传递一个参数数组。

参数

源代码
名称类型描述必需
name字符串

要调用的方法名称

argsArray.<EJSONable>

方法参数

options对象

选项

名称类型描述必需
wait布尔值

(仅限客户端)如果为 true,则不要发送此方法,直到所有先前的方法调用都已完成,并且在该方法完成之前不要发送任何后续方法调用。

onResultReceived函数

(仅限客户端)此回调在错误或结果可用时立即使用方法的错误或结果(就像 asyncCallback 一样)调用。本地缓存可能尚未反映方法执行的写入。

noRetry布尔值

(仅限客户端)如果为 true,则在重新加载时不要再次发送此方法,只需使用错误代码“invocation-failed”调用回调即可。

throwStubExceptions布尔值

(仅限客户端)如果为 true,则方法存根抛出的异常将被抛出而不是记录,并且不会在服务器上调用该方法。

returnStubValue布尔值

(仅限客户端)如果为 true,则在我们会丢弃存根的返回值并返回 undefined 的情况下,我们会继续返回它。具体来说,这是除以下情况之外的任何时候:(a)我们已经在存根内部或(b)我们在 Node 中并且没有提供回调。目前,我们要求显式传递此标志,以降低存根返回值与服务器返回值混淆的可能性;我们可能会在将来改进这一点。

returnServerResultPromise布尔值

(仅限客户端)如果为 true,则 applyAsync 返回的 promise 将解析为服务器的返回值,而不是存根的返回值。当您希望确保使用服务器的返回值(即使存根返回 promise)时,这很有用。与 callAsync 相同的行为。

js
import { Meteor } from "meteor/meteor";


const result = Meteor.applyAsync();
  "name",
[{ num: 42 , someProp: "foo" }],
options, // this param is optional
);

Meteor.applyAsync 就像 Meteor.apply 一样,只是它是一个异步函数,并且它会认为存根是异步的。

发布和订阅

这些函数控制 Meteor 服务器如何发布记录集以及客户端如何订阅这些记录集。

Meteor.publish

仅限服务器

摘要

发布记录集。

要将记录发布到客户端,请在服务器上使用两个参数调用 Meteor.publish:记录集的名称和每次客户端订阅该名称时 Meteor 将调用的_发布函数_。

发布函数可以返回一个Collection.Cursor,在这种情况下,Meteor 将将该游标的文档发布到每个订阅的客户端。您还可以返回一个 Collection.Cursor 数组,在这种情况下,Meteor 将发布所有游标。

警告

如果在一个数组中返回多个游标,它们当前必须都来自不同的集合。我们希望在未来的版本中取消此限制。

参数

源代码
名称类型描述必需
name字符串或对象

如果是字符串,则为记录集的名称。如果是对象,则为发布函数的 publications 字典,按名称区分。如果是 null,则该集合没有名称,并且记录集会自动发送到所有连接的客户端。

func函数

每次客户端订阅时在服务器上调用的函数。在函数内部,this 是发布处理程序对象,如下所述。如果客户端向 subscribe 传递了参数,则使用相同的参数调用该函数。

js
import { Meteor } from "meteor/meteor";
import { check } from "meteor/check";
import { Rooms } from "/imports/api/Rooms";
import { Messages } from "/imports/api/Messages";

// Server: Publish the `Rooms` collection, minus secret info...
Meteor.publish("rooms", function () {
  return Rooms.find(
    {},
    {
      fields: { secretInfo: 0 },
    }
  );
});

// ...and publish secret info for rooms where the logged-in user is an admin. If
// the client subscribes to both publications, the records are merged together
// into the same documents in the `Rooms` collection. Note that currently object
// values are not recursively merged, so the fields that differ must be top
// level fields.
Meteor.publish("adminSecretInfo", function () {
  return Rooms.find(
    { admin: this.userId },
    {
      fields: { secretInfo: 1 },
    }
  );
});

// Publish dependent documents and simulate joins.
Meteor.publish("roomAndMessages", function (roomId) {
  check(roomId, String);

  return [
    Rooms.find(
      { _id: roomId },
      {
        fields: { secretInfo: 0 },
      }
    ),
    Messages.find({ roomId }),
  ];
});

或者,发布函数可以通过调用函数 added(向发布的记录集中添加新文档)、changed(更改或清除已发布记录集中文档的一些字段)和 removed(从发布的记录集中删除文档)来直接控制其发布的记录集。这些方法由发布函数中的 this 提供。

如果发布函数不返回游标或游标数组,则假定它使用低级 added/changed/removed 接口,并且**还必须在初始记录集完成后调用一次 ready**。

js
import { Mongo } from "meteor/mongo";

export const Rooms = new Mongo.Collection("rooms");
export const SecretData = new Mongo.Collection("messages");
js
import { Meteor } from "meteor/meteor";
import { check } from "meteor/check";
import { Rooms, SecretData } from "/imports/api/collections";

// Publish the current size of a collection.
Meteor.publish("countsByRoom", function (roomId) {
  check(roomId, String);

  let count = 0;
  let initializing = true;

  // `observeChanges` only returns after the initial `added` callbacks have run.
  // Until then, we don't want to send a lot of `changed` messages—hence
  // tracking the `initializing` state.
  const handle = Messages.find({ roomId }).observeChanges({
    added: (id) => {
      count += 1;

      if (!initializing) {
        this.changed("counts", roomId, { count });
      }
    },

    removed: (id) => {
      count -= 1;
      this.changed("counts", roomId, { count });
    },

    // We don't care about `changed` events.
  });

  // Instead, we'll send one `added` message right after `observeChanges` has
  // returned, and mark the subscription as ready.
  initializing = false;
  this.added("counts", roomId, { count });
  this.ready();

  // Stop observing the cursor when the client unsubscribes. Stopping a
  // subscription automatically takes care of sending the client any `removed`
  // messages.
  this.onStop(() => handle.stop());
});

// Sometimes publish a query, sometimes publish nothing.
Meteor.publish("secretData", function () {
  if (this.userId === "superuser") {
    return SecretData.find();
  } else {
    // Declare that no data is being published. If you leave this line out,
    // Meteor will never consider the subscription ready because it thinks
    // you're using the `added/changed/removed` interface where you have to
    // explicitly call `this.ready`.
    return [];
  }
});
js
import { Meteor } from "meteor/meteor";
import { Mongo } from "meteor/mongo";
import { Session } from "meteor/session";
// Declare a collection to hold the count object.
const Counts = new Mongo.Collection("counts");

// Subscribe to the count for the current room.
Tracker.autorun(() => {
  Meteor.subscribe("countsByRoom", Session.get("roomId"));
});

// Use the new collection.
const roomCount = Counts.findOne(Session.get("roomId")).count;
console.log(`Current room has ${roomCount} messages.`);

警告

如果在包含 autopublish 包的项目中调用 Meteor.publish,Meteor 将发出警告消息。您的发布函数仍然可以工作。

在 Meteor 指南的 数据加载 文章中阅读有关发布和如何使用发布的更多信息。

this.userId

仅限服务器

摘要

在发布函数内部访问。已登录用户的 ID,如果没有任何用户登录则为 null

这是常量。但是,如果已登录的用户发生更改,则发布函数将使用新值重新运行,假设它在之前的运行中没有抛出错误。

this.added

仅限服务器

摘要

在发布函数内部调用。通知订阅者已将文档添加到记录集中。

参数

源代码
名称类型描述必需
集合字符串

包含新文档的集合的名称。

ID字符串

新文档的 ID。

字段对象

新文档中的字段。如果存在 _id,则会忽略它。

js

// this is an instance of Subscription

const result = this.added();
  "collection",
"id",

fields,
);

this.changed

仅限服务器

摘要

在发布函数内部调用。通知订阅者记录集中的文档已修改。

参数

源代码
名称类型描述必需
集合字符串

包含已更改文档的集合的名称。

ID字符串

已更改文档的 ID。

字段对象

文档中已更改的字段及其新值。如果 fields 中不存在某个字段,则表示该字段未更改;如果 fields 中存在该字段且其值为 undefined,则表示该字段已从文档中删除。如果存在 _id,则会忽略它。

js

// this is an instance of Subscription

const result = this.changed();
  "collection",
"id",

fields,
);

this.removed

仅限服务器

摘要

在发布函数内部调用。通知订阅者已从记录集中删除文档。

参数

源代码
名称类型描述必需
集合字符串

已从中删除文档的集合的名称。

ID字符串

已删除的文档的 ID。

js

// this is an instance of Subscription

const result = this.removed();
  "collection",
"id",
);

this.ready

仅限服务器

摘要

在发布函数内部调用。通知订阅者已发送记录集的初始完整快照。这将触发对客户端上传递给 Meteor.subscribe(如果有)的 onReady 回调的调用。

js

// this is an instance of Subscription

const result = this.ready();

this.onStop

仅限服务器

摘要

在发布函数内部调用。注册一个回调函数,在订阅停止时运行。

参数

源代码
名称类型描述必需
func函数

回调函数

js

// this is an instance of Subscription

const result = this.onStop();
  () => {}
);

如果在发布处理程序中调用 observeobserveChanges,则此处是停止观察的位置。

this.error

仅限服务器

摘要

在发布函数内部调用。停止此客户端的订阅,触发对客户端上传递给 Meteor.subscribe(如果有)的 onStop 回调的调用。如果 error 不是 Meteor.Error,它将被 清理

参数

源代码
名称类型描述必需
error错误

要传递给客户端的错误。

js

// this is an instance of Subscription

const result = this.error();
  Error(error)
);

this.stop

仅限服务器

摘要

在发布函数内部调用。停止此客户端的订阅并调用客户端的 onStop 回调,不带任何错误。

js

// this is an instance of Subscription

const result = this.stop();

this.connection

仅限服务器

摘要

在发布函数内部访问。此订阅的传入 连接

Meteor.subscribe

仅限客户端

摘要

订阅记录集。返回一个句柄,该句柄提供 stop()ready() 方法。

参数

源代码
名称类型描述必需
name字符串

订阅的名称。与服务器的 publish() 调用的名称匹配。

arg1, arg2...EJSONable

传递给服务器上发布者函数的可选参数。

回调函数或对象

可选。可能包括 onStoponReady 回调。如果发生错误,则将其作为参数传递给 onStop。如果传递函数而不是对象,则将其解释为 onReady 回调。

订阅记录集时,它会告诉服务器将记录发送到客户端。客户端将这些记录存储在本地 Minimongo 集合 中,其名称与发布处理程序的 addedchangedremoved 回调中使用的 collection 参数相同。在客户端使用匹配的集合名称声明 Mongo.Collection 之前,Meteor 将对传入的记录进行排队。

js
// It's okay to subscribe (and possibly receive data) before declaring the
// client collection that will hold it. Assume 'allPlayers' publishes data from
// the server's 'players' collection.
Meteor.subscribe("allPlayers");

// The client queues incoming 'players' records until the collection is created:
const Players = new Mongo.Collection("players");

如果文档当前位于其任何订阅的已发布记录集中,则客户端将看到该文档。如果多个发布使用相同的 _id 发布同一集合的文档,则会为客户端合并这些文档。如果任何顶级字段的值发生冲突,则结果值将是已发布的值之一,任意选择。

警告

当前,当多个订阅发布同一文档时,仅比较顶级字段。这意味着如果文档包含同一顶级字段的不同子字段,则并非所有子字段都将在客户端上可用。我们希望在未来的版本中取消此限制。

当服务器 将订阅标记为已准备就绪 时,将不带任何参数调用 onReady 回调。如果订阅失败或被服务器终止,则将使用 Meteor.Error 调用 onStop 回调。如果通过调用订阅句柄上的 stop 或在发布内部停止订阅,则将不带任何参数调用 onStop

Meteor.subscribe 返回一个订阅句柄,它是一个具有以下属性的对象

ts
import { Meteor } from "meteor/meteor";
const handle = Meteor.subscribe("allPlayers");

handle.ready(); // True when the server has marked the subscription as ready

handle.stop(); // Stop this subscription and unsubscribe from the server

handle.subscriptionId; // The id of the subscription this handle is for.

在 Tracker.autorun 内部运行 Meteor.subscribe 时,获得的句柄将始终具有相同的 subscriptionId 字段。如果将这些句柄存储在某些数据结构中,则可以使用它来对订阅句柄进行去重。

如果在反应式计算中调用 Meteor.subscribe,例如使用 Tracker.autorun,则当计算失效或停止时,订阅将自动取消;无需对从 autorun 内部进行的订阅调用 stop。但是,如果运行函数的下一个迭代订阅了相同的记录集(相同的名称和参数),则 Meteor 足够智能,可以跳过浪费的取消订阅/重新订阅。例如

js
Tracker.autorun(() => {
  Meteor.subscribe("chat", { room: Session.get("currentRoom") });
  Meteor.subscribe("privateMessages");
});

这会让你订阅当前房间的聊天消息和你私人的消息。当你通过调用 Session.set('currentRoom', 'newRoom') 更改房间时,Meteor 将订阅新房间的聊天消息,取消订阅原始房间的聊天消息,并继续保持订阅你的私人消息。

发布策略

以下功能适用于 Meteor 2.4 或 [email protected]

一旦开始扩展应用程序,您可能希望更多地控制客户端如何处理发布中的数据。有三种发布策略

SERVER_MERGE

SERVER_MERGE 是默认策略。使用此策略时,服务器会维护连接订阅的所有数据的副本。这使我们能够仅通过多个发布发送增量。

NO_MERGE_NO_HISTORY

NO_MERGE_NO_HISTORY 策略会导致服务器将所有发布数据直接发送到客户端。它不记得以前发送给客户端的内容,并且在订阅停止时不会触发删除消息。这仅应在特殊用例(如发送并忘记队列)中选择。

NO_MERGE

NO_MERGENO_MERGE_NO_HISTORY 类似,但服务器会记住已发送给客户端的 ID,以便在订阅停止时可以删除它们。当集合仅在一个发布中使用时,可以使用此策略。

选择 NO_MERGE 后,客户端将优雅地处理重复事件,而不会抛出异常。具体来说

  • 当我们收到已存在于客户端集合中的文档的添加消息时,它将被更改。
  • 当我们收到客户端集合中不存在的文档的更改消息时,它将被添加。
  • 当我们收到客户端集合中不存在的文档的删除消息时,不会发生任何事情。

您可以从 DDPServer 导入发布策略。

js
import { DDPServer } from "meteor/ddp-server";

const { SERVER_MERGE, NO_MERGE_NO_HISTORY, NO_MERGE } =
  DDPServer.publicationStrategies;

您可以使用以下方法设置或获取发布的发布策略

setPublicationStrategy

仅限服务器

摘要

设置给定集合的发布策略。发布策略可从 DDPServer.publicationStrategies 获取。您可以从 Meteor.server 调用此方法,例如 Meteor.server.setPublicationStrategy()

参数

源代码
名称类型描述必需
collectionName字符串----
策略对象----

对于 foo 集合,您可以设置 NO_MERGE 策略,如所示

js
import { DDPServer } from "meteor/ddp-server";
Meteor.server.setPublicationStrategy(
  "foo",
  DDPServer.publicationStrategies.NO_MERGE
);

getPublicationStrategy

仅限服务器

摘要

获取请求的集合的发布策略。您可以从 Meteor.server 调用此方法,例如 Meteor.server.getPublicationStrategy()

参数

源代码
名称类型描述必需
collectionName字符串----
js
import { Meteor } from "meteor/meteor";

/** @returns Object */
const result = Meteor.server.getPublicationStrategy();
  "collectionName"
);

服务器连接

用于管理和检查 Meteor 客户端与服务器之间网络连接的函数。

Meteor.status

仅限客户端

摘要

获取当前连接状态。一个响应式数据源。

js
import { Meteor } from "meteor/meteor";
const status = Meteor.status();

console.log(status);
//          ^^^^
// {
//   connected: Boolean,
//   status: String,
//   retryCount: Number,
//   retryTime: Number,
//   reason: String,
// }

状态对象包含以下字段

  • connected - 布尔值:如果当前已连接到服务器,则为真。如果为假,则更改和方法调用将排队,直到重新建立连接。
  • status - 字符串:描述当前的重新连接状态。可能的值包括 connected(连接已建立并运行)、connecting(已断开连接并尝试打开新连接)、failed(永久连接失败;例如,客户端和服务器支持不同的 DDP 版本)、waiting(连接失败并等待尝试重新连接)和 offline(用户已断开连接)。
  • retryCount - 数字:连接丢失后,客户端尝试重新连接的次数。连接时为 0。
  • retryTime - 数字或未定义:下一次重新连接尝试的估计时间。要将其转换为下一次重新连接之前的间隔,此键仅在 statuswaiting 时设置。您可以使用此代码段
    js
    retryTime - new Date().getTime();
  • reason - 字符串或未定义:如果 statusfailed,则说明连接失败的原因。

Meteor.reconnect

仅限客户端

摘要

如果客户端未连接到服务器,则强制立即尝试重新连接。

如果客户端已连接,则此方法不执行任何操作。

js
import { Meteor } from "meteor/meteor";


const result = Meteor.reconnect();

Meteor.disconnect

仅限客户端

摘要

断开客户端与服务器的连接。

js
import { Meteor } from "meteor/meteor";


const result = Meteor.disconnect();

调用此方法可断开与服务器的连接并停止所有实时数据更新。在客户端断开连接期间,它不会接收集合的更新,方法调用将排队,直到重新建立连接,并且热代码推送将被禁用。

调用 Meteor.reconnect 以重新建立连接并恢复数据传输。

这可用于在不需要实时更新时节省移动设备的电量。

Meteor.onConnection

仅限服务器

摘要

注册一个回调函数,在与服务器建立新的 DDP 连接时调用。

参数

源代码
名称类型描述必需
回调函数函数

在建立新的 DDP 连接时要调用的函数。

js
import { Meteor } from "meteor/meteor";

const handle = Meteor.onConnection((connection) => {
  console.log(connection);
  //          ^^^^^^^^^^^
  // {
  //   id: String,
  //   close: Function,
  //   onClose: Function,
  //   clientAddress: String,
  //   httpHeaders: Object,
  // }
});

handle.stop(); // Unregister the callback

onConnection 返回一个包含单个方法 stop 的对象。调用 stop 将取消注册回调函数,以便此回调函数不再在新的连接上被调用。

回调函数将接收一个参数,即表示客户端连接的服务器端 connection 对象。此对象包含以下字段

  • id - 字符串:此连接的全局唯一 ID。

  • close - 函数:关闭此 DDP 连接。客户端可以自由重新连接,但如果重新连接,则会收到具有新 id 的不同连接。

  • onClose - 函数:注册一个回调函数,在连接关闭时调用。如果连接已关闭,则会立即调用回调函数。

  • clientAddress - 字符串:客户端的 IP 地址,采用点分十进制格式(例如 127.0.0.1)。如果您在代理服务器后面运行 Meteor 服务器(以便客户端连接到代理服务器而不是直接连接到您的服务器),则需要设置 HTTP_FORWARDED_COUNT 环境变量,以便 clientAddress 报告正确的 IP 地址。

    HTTP_FORWARDED_COUNT 设置为一个整数,表示服务器前面的代理服务器数量。例如,当您的服务器位于一个代理服务器后面时,您将其设置为 1

  • httpHeaders - 对象:当连接通过 HTTP 传输(例如使用 Meteor 的默认 SockJS 实现)时,此字段包含白名单 HTTP 标头。

    出于安全考虑,Cookie 会故意从标头中排除,因为它们对这种传输方式构成安全风险。有关详细信息和替代方案,请参阅 SockJS 文档

当前,当客户端重新连接到服务器(例如在暂时失去 Internet 连接后),它每次都会获得一个新的连接。onConnection 回调函数将再次被调用,并且新连接将具有新的连接 id

将来,当客户端重新连接完全实现后,从客户端重新连接将重新连接到服务器上的同一连接:onConnection 回调函数将不再为此连接调用,并且连接仍将具有相同的连接 id

DDP.connect

摘要

连接到另一个 Meteor 应用程序的服务器,以订阅其文档集并调用其远程方法。

参数

源代码
名称类型描述必需
url字符串

另一个 Meteor 应用程序的 URL。

options对象

选项

名称类型描述必需
reloadWithOutstanding布尔值

如果存在未完成的方法,是否可以重新加载?

headers对象

要发送到 WebSockets 连接的额外标头,仅限服务器到服务器的 DDP

_sockjsOptions对象

指定要传递给 sockjs 客户端的选项

onDDPNegotiationVersionFailure函数

版本协商失败时的回调函数。

js
import { DDP } from "meteor/ddp-client";
import { Mongo } from "meteor/mongo";
import { Meteor } from "meteor/meteor";
const options = {...};

const otherServer = DDP.connect("http://example.com", options);

otherServer.call("foo.from.other.server", 1, 2, function (err, result) {
  // ...
});

Metepr.call("foo.from.this.server", 1, 2, function (err, result) {
  // ...
});
const remoteColl = new Mongo.Collection("collectionName", { connection: otherServer });
remoteColl.find(...);

要调用另一个 Meteor 应用程序上的方法或订阅其数据集,请使用应用程序的 URL 调用 DDP.connectDDP.connect 返回一个对象,该对象提供

默认情况下,客户端会打开与加载它们的服务器的连接。当您调用 Meteor.subscribeMeteor.statusMeteor.callMeteor.apply 时,您正在使用连接返回到该默认服务器。

DDP.onReconnect

摘要

注册一个函数,作为重新连接的第一步调用。此函数可以调用将在任何其他未完成方法之前执行的方法。例如,这可用于在连接上重新建立适当的身份验证上下文。

参数

源代码
名称类型描述必需
回调函数函数

要调用的函数。它将接收一个参数,即正在重新连接的 连接对象

js
import { DDP } from "meteor/ddp-client";


const result = DDP.onReconnect();
  () => {}
);

计时器

Meteor 使用全局环境变量来跟踪诸如当前请求的用户之类的事情。为了确保这些变量具有正确的价值,您需要使用 Meteor.setTimeout 而不是 setTimeout 以及 Meteor.setInterval 而不是 setInterval

这些函数的工作原理与其本机 JavaScript 等效项完全相同。如果您调用本机函数,您将收到一条错误消息,指出 Meteor 代码必须始终在 Fiber 中运行,并建议使用 Meteor.bindEnvironment

Meteor.setTimeout

摘要

在等待指定延迟后,将来调用一个函数。

参数

源代码
名称类型描述必需
func函数

要运行的函数

延迟数字

在调用函数之前要等待的毫秒数

js
import { Meteor } from "meteor/meteor";


const result = Meteor.setTimeout();
  () => {},
42,
);

返回一个句柄,可由 Meteor.clearTimeout 使用。

Meteor.setInterval

摘要

重复调用一个函数,并在每次调用之间设置时间延迟。

参数

源代码
名称类型描述必需
func函数

要运行的函数

延迟数字

每次函数调用之间要等待的毫秒数。

js
import { Meteor } from "meteor/meteor";


const result = Meteor.setInterval();
  () => {},
42,
);

返回一个句柄,可由 Meteor.clearInterval 使用。

Meteor.clearTimeout

摘要

取消由 Meteor.setTimeout 调度的函数调用。

参数

源代码
名称类型描述必需
ID对象

Meteor.setTimeout 返回的句柄

js
import { Meteor } from "meteor/meteor";


const result = Meteor.clearTimeout();
  id
);

Meteor.clearInterval

摘要

取消由 Meteor.setInterval 调度的重复函数调用。

参数

源代码
名称类型描述必需
ID对象

Meteor.setInterval 返回的句柄

js
import { Meteor } from "meteor/meteor";


const result = Meteor.clearInterval();
  id
);

环境变量

Meteor 使用 AsyncLocalStorage 实现 Meteor.EnvironmentVariable,它允许跨异步边界维护上下文。Meteor.EnvironmentVariableMeteor.bindEnvironment、Promise 和许多其他 Meteor API 协同工作,以在异步代码中保留上下文。它在 Meteor 中的一些使用示例是在方法中存储当前用户,以及在使用 audit-argument-checks 时记录已检查的参数。

js
import { Meteor } from "meteor/meteor";
const currentRequest = new Meteor.EnvironmentVariable();

function log(message) {
  const requestId = currentRequest.get() || "None";
  console.log(`[${requestId}]`, message);
}

currentRequest.withValue("12345", () => {
  log("Handling request"); // Logs: [12345] Handling request
});

Meteor.EnvironmentVariable

摘要

EnvironmentVariable 的构造函数

js
import { Meteor } from "meteor/meteor"";

const environmentVariable = new Meteor.EnvironmentVariable();

);

Meteor.EnvironmentVariableAsync

摘要

EnvironmentVariable 的构造函数

js
import { Meteor } from "meteor/meteor"";

const environmentVariableAsync = new Meteor.EnvironmentVariableAsync();

);

Meteor.EnvironmentVariable.get

摘要

变量当前值的获取器,如果从 withValue 回调函数外部调用,则为 undefined

js
import { Meteor } from "meteor/meteor";

/** @returns any */
const result = Meteor.EnvironmentVariable.get();

Meteor.EnvironmentVariable.withValue

摘要

接收一个值和一个函数,在调用期间设置该值并调用该函数

参数

源代码
名称类型描述必需
任意

在函数调用期间要设置的值

func函数

要使用新值调用的函数

options对象

用于添加 asl 的可选附加属性

js
import { Meteor } from "meteor/meteor";

/** @returns Promise<any> */
const result = Meteor.EnvironmentVariable.withValue();
  any,
() => {},

options, // this param is optional
);

Meteor.bindEnvironment

摘要

存储当前的 Meteor 环境变量,并包装要使用恢复的环境变量运行的函数。在服务器上,该函数在 Async Local Storage 中包装。

此函数有两个原因

  1. 返回要在 MeteorJS 上下文中执行的函数,将其分配在 Async Local Storage 中。
  2. 更好的错误处理,错误消息将更加清晰。

参数

源代码
名称类型描述必需
func函数

要包装的函数

onException函数----
_this对象

可选的 this 对象,原始函数将针对其调用

js
import { Meteor } from "meteor/meteor";

/** @returns function */
const result = Meteor.bindEnvironment();
  () => {},
() => {},

_this,
);