From 8fe08ac9e7389ca324479054113b4a608350451f Mon Sep 17 00:00:00 2001 From: sebastianspiller Date: Tue, 24 Oct 2023 14:51:14 +0200 Subject: [PATCH 1/4] Documentation update to make Tracker.withComputation more understandable --- docs/source/api/tracker.md | 50 +++++++++++++++----------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/docs/source/api/tracker.md b/docs/source/api/tracker.md index 6e2cf2dee2..340ef0ace1 100644 --- a/docs/source/api/tracker.md +++ b/docs/source/api/tracker.md @@ -81,45 +81,33 @@ is automatically stopped and won't be rerun. ### Tracker.autorun and async callbacks `Tracker.autorun` can accept an `async` callback function. -However, to make the async call reactive, you should wrap your async function in -a `Tracker.withComputation` call. - -```javascript -Tracker.autorun(async function example1(computation) { - let asyncData = await asyncDataFunction(); - let users = - await Tracker.withComputation(computation, () => Meteor.users.find({}).fetch()); -}); -``` -> If you want to get computation in other way you can use `Tracker.currentComputation` - + To preserve reactivity for the reactive variables inside the async callback function, you must use a `Tracker.withComputation` call as described below: {% apibox "Tracker.withComputation" %} -In general, the rules to use `Tracker.withComputation` like this: -1. `async` function *before the first* `await` if just like a sync one. -2. `async` function *after the first* `await` looses the `Tracker.currentComputation` -but it can be restored using `Tracker.withComputation`, *but only within the callback*. - -If you have for example: - ```javascript -Tracker.autorun(async function (computation) { - let asyncData = await someAsyncCall(); - let links = await LinksCollection.find({}).fetch(); - // code above will not trigger reruns. -}); -``` -You can make this example reactive by wrapping the `Meteor.users.find` call in a `Tracker.withComputation` call: +Tracker.autorun(async function example1(computation) { + // Code before the first await will stay reactive. + reactiveVar1.get() // will trigger rerun -```javascript -Tracker.autorun(async function (computation) { - let asyncData = await someAsyncCall(); + let links = await LinksCollection.findAsync({}).fetch(); // first async call will stay reactive. + + // Code after the first await looses Tracker.currentComputation: no reactivity. + reactiveVar2.get() // won't trigger rerun + + // You can bring back reactivity with the Tracker.withCompuation wrapper: let users = - await Tracker.withComputation(computation, () => Meteor.users.find({}).fetch()); - // code above will trigger reruns. + await Tracker.withComputation(computation, () => Meteor.users.findAsync({}).fetch()); + + // Code below will again not be reactive, so you will need another Tracker.withComputation + const value = Tracker.withComputation(computation, () => reactiveVar3.get()) // will trigger rerun }); ``` + +As a rule of thumb, you are fine with wrapping all reactive statements inside a Tracker.withComputation to preserve current computation. + +Reason is, that an await implicitly *"moves"* the code below in a Promise resolved function. When this function runs (after it has been fetched from the micro task queue), Tracker.withComputation preserves the reference to the computation of the Tracker.autorun. + The `react-meteor-data` package uses `Tracker.withComputation` to make the `useTracker` accept async callbacks. More can be seen [here](https://github.com/meteor/react-packages/tree/master/packages/react-meteor-data#maintaining-the-reactive-context) From 9eb5e670dbd1399728fe55ceae8687135d9cadaa Mon Sep 17 00:00:00 2001 From: harryadel Date: Mon, 30 Oct 2023 14:08:02 +0200 Subject: [PATCH 2/4] Fix links in tracker README --- packages/tracker/README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/tracker/README.md b/packages/tracker/README.md index 33448d8caf..ad3a22cba8 100644 --- a/packages/tracker/README.md +++ b/packages/tracker/README.md @@ -50,7 +50,7 @@ The current temperature is 71.9 F (printed a few minutes later) The function passed to `Tracker.autorun` is called once immediately, and then it's called again whenever there are any changes to any of the _reactive data sources_ that it referenced. To make this work, `currentTemperatureCelsius` just needs to register with Tracker as a reactive data source when it's called, which takes only a few lines of code. -Or, instead of calling `Tracker.autorun` ourselves, we might use `currentTemperatureFahrenheit` in a [Blaze](https://www.meteor.com/blaze) template: +Or, instead of calling `Tracker.autorun` ourselves, we might use `currentTemperatureFahrenheit` in a [Blaze](https://www.blazejs.org/) template: ```handlebars @@ -100,9 +100,9 @@ It's easy for a library to detect if Tracker is available, and cooperate with it The Meteor project provides a variety of Tracker-aware libraries: -- [Blaze](https://www.meteor.com/blaze) is a reactive templating/DOM update library designed to work well with Tracker. +- [Blaze](https://www.blazejs.org/) is a reactive templating/DOM update library designed to work well with Tracker. -- [Minimongo](https://www.meteor.com/mini-databases) is a Tracker-aware reimplementation of the MongoDB API in JavaScript, very useful for storing and querying client-side data. We also have a ["full stack database driver"](https://www.meteor.com/full-stack-db-drivers) for Mongo that replicates data from a real server-side MongoDB database into Minimongo. +- [Minimongo](https://github.com/meteor/meteor/tree/devel/packages/minimongo) is a Tracker-aware reimplementation of the MongoDB API in JavaScript, very useful for storing and querying client-side data. We also have a ["full stack database driver"](https://docs.meteor.com/api/collections.html#Mongo-Collection) for Mongo that replicates data from a real server-side MongoDB database into Minimongo. - [reactive-dict](https://atmospherejs.com/meteor/reactive-dict), and [reactive-var](https://atmospherejs.com/meteor/reactive-var) provide @@ -113,7 +113,7 @@ code. - Other Meteor core packages are generally Tracker-aware wherever it makes sense. For example, the current connection status is reactive - in Meteor's [DDP](https://www.meteor.com/ddp) implementation, and + in Meteor's [DDP](https://github.com/meteor/meteor/tree/devel/packages/ddp) implementation, and the currently logged in user is reactive in [Meteor Accounts](https://docs.meteor.com/api/accounts) system. @@ -126,4 +126,3 @@ Ideas for future work include: - Providing a contract for _settable_ reactive values, to make it easier to build bidirectionally bound forms. There is some discussion of this [here](https://meteor.hackpad.com/Lickable-Forms-and-Components-6CVspZsVwJY). - Making it possible to control invalidation order, for example by specifying that if autorun B was created inside autorun A, then if both A and B are invalidated and eligible to be rerun, then A will rerun before B. It is easy to construct theoretical situations where this would be valuable, but situations where this makes a difference in real apps seem to be surprisingly rare. -Also as described on the project pages for [Mini databases](https://www.meteor.com/mini-databases) and [Full stack database drivers](https://www.meteor.com/full-stack-db-drivers), the Meteor project intends to eventually sponsor development of Tracker-aware libraries that emulate other server-side databases besides Mongo. From ad39c9d7467c09becfb96d2cf102476024715a19 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sun, 5 Nov 2023 18:02:29 +0100 Subject: [PATCH 3/4] Document into docs Accounts rate limiting functions --- docs/source/api/accounts-multi.md | 4 ++++ packages/accounts-base/accounts_server.js | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/source/api/accounts-multi.md b/docs/source/api/accounts-multi.md index 77cd5e259e..f4c92218f4 100644 --- a/docs/source/api/accounts-multi.md +++ b/docs/source/api/accounts-multi.md @@ -346,3 +346,7 @@ of legitimate users by attempting all possible passwords. These rate limiting rules can be removed by calling `Accounts.removeDefaultRateLimit()`. Please see the [`DDPRateLimiter`](#ddpratelimiter) docs for more information. + +{% apibox "AccountsServer#addDefaultRateLimit" %} + +{% apibox "AccountsServer#removeDefaultRateLimit" %} diff --git a/packages/accounts-base/accounts_server.js b/packages/accounts-base/accounts_server.js index be8e2b0bcf..c304ff772e 100644 --- a/packages/accounts-base/accounts_server.js +++ b/packages/accounts-base/accounts_server.js @@ -1364,15 +1364,23 @@ export class AccountsServer extends AccountsCommon { } }; - // Removes default rate limiting rule + /** + * @summary Removes default rate limiting rule + * @locus Server + * @importFromPackage accounts-base + */ removeDefaultRateLimit() { const resp = DDPRateLimiter.removeRule(this.defaultRateLimiterRuleId); this.defaultRateLimiterRuleId = null; return resp; }; - // Add a default rule of limiting logins, creating new users and password reset - // to 5 times every 10 seconds per connection. + /** + * @summary Add a default rule of limiting logins, creating new users and password reset + * to 5 times every 10 seconds per connection. + * @locus Server + * @importFromPackage accounts-base + */ addDefaultRateLimit() { if (!this.defaultRateLimiterRuleId) { this.defaultRateLimiterRuleId = DDPRateLimiter.addRule({ From 1baba8e689787822cd55e20c558c231ff2dd0da3 Mon Sep 17 00:00:00 2001 From: sebastianspiller Date: Mon, 6 Nov 2023 08:12:48 +0100 Subject: [PATCH 4/4] Cleaned up own documentation changes --- docs/source/api/tracker.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/source/api/tracker.md b/docs/source/api/tracker.md index 340ef0ace1..ee1b7daae3 100644 --- a/docs/source/api/tracker.md +++ b/docs/source/api/tracker.md @@ -87,26 +87,26 @@ is automatically stopped and won't be rerun. ```javascript Tracker.autorun(async function example1(computation) { - // Code before the first await will stay reactive. - reactiveVar1.get() // will trigger rerun + // Code before the first await will stay reactive. + reactiveVar1.get(); // This will trigger a rerun. - let links = await LinksCollection.findAsync({}).fetch(); // first async call will stay reactive. + let links = await LinksCollection.findAsync({}).fetch(); // First async call will stay reactive. - // Code after the first await looses Tracker.currentComputation: no reactivity. - reactiveVar2.get() // won't trigger rerun + // Code after the first await looses Tracker.currentComputation: no reactivity. + reactiveVar2.get(); // This won't trigger a rerun. - // You can bring back reactivity with the Tracker.withCompuation wrapper: - let users = - await Tracker.withComputation(computation, () => Meteor.users.findAsync({}).fetch()); + // You can bring back reactivity with the Tracker.withCompuation wrapper: + let users = await Tracker.withComputation(computation, () => Meteor.users.findAsync({}).fetch()); - // Code below will again not be reactive, so you will need another Tracker.withComputation - const value = Tracker.withComputation(computation, () => reactiveVar3.get()) // will trigger rerun + // Code below will again not be reactive, so you will need another Tracker.withComputation. + const value = Tracker.withComputation(computation, () => reactiveVar3.get()); // This will trigger a rerun. }); ``` -As a rule of thumb, you are fine with wrapping all reactive statements inside a Tracker.withComputation to preserve current computation. +As a rule of thumb, you are okay with wrapping all reactive statements inside a `Tracker.withComputation` to preserve current computation. +But it comes at a performance cost - it should be used only where needed. -Reason is, that an await implicitly *"moves"* the code below in a Promise resolved function. When this function runs (after it has been fetched from the micro task queue), Tracker.withComputation preserves the reference to the computation of the Tracker.autorun. +Reason behind is, that an await implicitly *"moves"* the code below in a Promise resolved function. When this function runs (after it has been fetched from the micro task queue), `Tracker.withComputation` preserves the reference to the computation of the `Tracker.autorun`. The `react-meteor-data` package uses `Tracker.withComputation` to make the `useTracker` accept async callbacks. More can be seen [here](https://github.com/meteor/react-packages/tree/master/packages/react-meteor-data#maintaining-the-reactive-context)