Four Kitchens
Insights

Building performant Meteor applications

4 Min. ReadDevelopment

This post is the fourth in a series of posts about the new JavaScript framework Meteor. If you are unfamiliar with Meteor check out the introduction post in this series or go through the demos available on Meteor’s project website.

In this post I’m going to show you some techniques for building performant Meteor-based applications. I won’t dig into server optimization or JavaScript optimization. Those are two completely different subjects that merit another (much longer) blog post. However in this post I am going to show you how to manage large data sets properly, and give you some basic optimization tips that will help you makes sure your app is quick and useable.

Managing large datasets

I recently worked on a Meteor-based application that had an extremely large set of data. In Meteor terms, there was a collection that contained a lot of very large documents. There are some things you can do from the get go that will make dealing with these large datasets easier.

Publish only the data you need

When you build your publish functions (the functions that send data to the client) make sure that you only return documents that you need within your client. This means that you might need to define a lot of publication functions, or that your publication functions might get more complicated, but it is absolutely necessary because throwing lots of data into your client will (obviously) slow the interface down, and make interactions sluggish.

For example, lets say you are rendering a list of data from a collection that contains 1000 documents. You don’t want all 1000 of those documents be stored in the browser at once, especially since you most likely don’t need that many documents. Instead, you should paginate your list by passing a page or offset to the publication function from your subscription. Then in your publication function you can filter your query by the passed-in offset, and return only the documents needed to render the current page. This is easy to do, and thanks to the reactive pub/sub system in meteor, all you have to do to change the page is pass a new page number into your publication function, Meteor will handle the rest.

As another example, you might have documents within a collection that reference other documents within another collection. You might also need to access properties of the referenced documents on the client. In this instance, it’s usually best to return an array of cursors from your publication as opposed to a single cursor of documents. One cursor should contain the initial documents and another should contain only the referenced documents. This will ensure that you can access properties of the referenced objects without forming multiple subscriptions on the client side. It will only publish the referenced documents that you need as opposed to all the documents within the referenced collection.

/**
 * Publishes orders and pizza for a given user.
 *
 * @param string userId
 *   User id for which orders should be returned.
 *
 * @return array
 *   Cursors of documents that should be sent to the client.
 */
Meteor.publish('ordersAndPizzaByUser', function(userId) {
  var ordersCursor = Orders.find({user: userId}),
      pizzaIds = ordersCursor.map(function (order) { return order.pizzaIds; }),
      pizzasCursor = Pizzas.find({_id: {$in: pizzaIds}});
  
  return [
    ordersCursor,
    pizzasCursor
  ];
});

Subscribe only to publications you need

On the client side of your application, only create subscriptions to publications that you need. If you have sets of documents from different collections that always go together, as I demonstrated in my previous example, create a publication function that returns sets of documents from both collections simultaneously.

Make sure js is published to the proper environment

Meteor publishes all JavaScript code to either the client, to the server, or to both. Since many parts of Meteor are isomorphic, it’s important to understand where your JavaScript is being published so that you don’t bloat the client with server code. Code files in the /meteor_root/server directory are published to the server, and code files in the /meteor_root/client directory are published to the client. Any files outside of these two folders (with the exception of /public and /private folders) is published to both. You should organize your code into these two folders to ensure that code is published to the appropriate environment. There are also truthy properties available on the Meteor object, Meteor.isClient and Meteor.isServer, which indicate the environment in which a block of of code is running in. These can be used within files that are published to both the client and the server, but should be used sparingly, as you don’t want to publish large blobs of server JavaScript to the client.

In general, if you follow these rules, you’ll avoid a large number of performance issues within your Meteor application. The basic principle is this: give the client only what it needs to function correctly. Having a well organized codebase and source tree can help you accomplish this, and you can find some tips on good architecture in an earlier post in this series.


This post was originally published on my personal blog here.