Meteor介绍

本文转自我的博客Meteor介绍

Meteor(流星)是什么

Meteor is a full-stack JavaScript platform for developing modern web and mobile applications. Meteor includes a key set of technologies for building connected-client reactive applications, a build tool, and a curated set of packages from the Node.js and general JavaScript community.

Meteor是一个full-stack javascript平台,可用于开发web和移动应用。其最大特点是其(通过websocket)保持客户端连接的“实时”框架。数据库(mongodb)的改变可“实时”展示到界面中。

以下列出优缺点更直观的了解meteor。

优点

实时

读取数据使用DDP

数据实时读取使用DDP(distributed data protocal)的pub/sub,一般是websocket实现的的pub/sub方式。

例如不停的请求第三方api来达到实时效果官方示例

const POLL_INTERVAL = 5000;

Meteor.publish('polled-publication', function() {
  const publishedKeys = {};

  const poll = () => {
    // Let's assume the data comes back as an array of JSON documents, with an _id field, for simplicity
    const data = HTTP.get(REST_URL, REST_OPTIONS);

    data.forEach((doc) => {
      if (publishedKeys[doc._id]) {
        this.changed(COLLECTION_NAME, doc._id, doc);
      } else {
        publishedKeys[doc._id] = true;
        this.added(COLLECTION_NAME, doc._id, doc);
      }
    });
  };

  poll();
  this.ready();

  const interval = Meteor.setInterval(poll, POLL_INTERVAL);

  this.onStop(() => {
    Meteor.clearInterval(interval);
  });
});

上例使用的是Meteor自带的DDP API的changed,added方法来实现数据publish, 这种方式有个问题,即没有通过mongodb,创建的是其实是local collection,那么它的改变只对当前连接(websocket)有效,无法做到多个clients共享。其实相当于为每个subscribe客户端创建一个同名local collection。

参见使用底层api自定义publication(Custom publications with the low level API)

Meteor.publish('custom-publication', function() {
  // We can add documents one at a time
  this.added('collection-name', 'id', {field: 'values'});

  // We can call ready to indicate to the client that the initial document sent has been sent
  this.ready();

  // We may respond to some 3rd party event and want to send notifications
  Meteor.setTimeout(() => {
    // If we want to modify a document that we've already added
    this.changed('collection-name', 'id', {field: 'new-value'});

    // Or if we don't want the client to see it any more
    this.removed('collection-name', 'id');
  });

  // It's very important to clean up things in the subscription's onStop handler
  this.onStop(() => {
    // Perhaps kill the connection with the 3rd party server
  });
});

首先需要明确,不管服务端数据源是否来自mongodb,客户端都有一个内存mongodb,客户端都是针对这个mongodb来查询操作。 详见这里

再来看看默认的基于服务端Mongodb数据实现:
使用的是MongoDB’s Oplog,对mongo数据库的修改得以立即广播到读取指针(cursor).
示例

Meteor.publish('lists.public', function() {
  return Lists.find({
    userId: {$exists: false}
  }, {
    fields: Lists.publicFields
  });
});

魔法就在于Lists.find,如果对应的集合有所变动,都会向客户端广播。
oplog也有一些限制 最主要的是,mongodb必须是replica set,否则还是默认的polling。这一下子就提高了门槛。 不过,polling对于同一个进程的修改反映还是蛮快的,而默认的meteor collection实现应该是一个进程中,故还不错。目前meteor1.7的版本使用的是mogon 3.0的driver,还不能使用driver3.1事务,如果自己新开一个cmongo client,则估计是在另外一个process,从测试结果来看,与meteor的collection更新时间间隔有5秒以上的差距,见示例.

修改数据使用method(也属于DDP协议)

method类似RPC; method有一些特点:

  • 客户端调用方法直接引用定义文件调用,直观。
  • 现在客户端调用验证,如果失败,就不会调用服务端。
  • 方便于测试。
不提倡从method获得数据

一般应该是从pub/sub获得数据,method只负责修改,不应该从method的返回获得数据。因为虽然method是能够返回数据的, 但这种情况下,你还得手动维护客户端mongodb的数据一致性。

// In client-side code, declare a local collection
// by passing `null` as the argument
ScoreAverages = new Mongo.Collection(null);

import { calculateAverages } from '../api/games/methods.js';

function updateAverages() {
  // Clean out result cache
  ScoreAverages.remove({});

  // Call a Method that does an expensive computation
  calculateAverages.call((err, res) => {
    res.forEach((item) => {
      ScoreAverages.insert(item);
    });
  });
}

Method相对于REST API的好处

基于Fibers,编写类似于同步方式的代码,但是不是阻塞(blocking)的

使用fibers将method(请求估计也是websocket,由于每个method都有id,将调用和返回通过id关联,将websocket异步的包装成同步的)封装成同步的形式,这样既保持了websocket的便利,也使得编码逻辑直观。 Fiber不是个新概念,它不同于thread,并不能起到thread的作用,个人理解,更像nodejs里面await/async的一种实现。 例如meteor里的method需要返回,是不支持callback的方式的,可以通过Meteor.wrapAsync来包装callback方式的调用。
举个例子

get: function() {
      var limit = this.queryParams.limit;
      limit = parseInt(limit) || 100;
      try {
        var results = Meteor.wrapAsync(callback => {
          service.listing({ limit }, (error, results, fields) => {
            if (error) {
              callback(error);
              return;
            }

            callback(null, results);
          });
        })();
        return results;
      } catch (err) {
        throw err;
      }
    }

请求和返回都是有序的

对于ajax请求,请求和返回不能保证有序,可能后请求的先得到返回。meteor保证了每个客户端的每个请求都是有序的,前一个调用成功后才进行下一个。不过对于特殊的情况,也可以改变这个机制而使得执行无序。例如this.unblock()

每个DDP(pub/sub和method)都可以是绑定用户信息的

通过this.userId可用于判断用户是否登录,用户系统可自定义,也可使用meteor的api。

商业支持,论坛支持,文档详细

meteor虽然开源,但背后有专门的商业公司支持,目前来看github上有40k+星标,项目活跃程度还算不错 其提供hosting服务,也提供商业支持服务,商业支持服务对于商业项目来说是很重要的考虑点。

meteor背后的团队是Meteor Development Group(MDG),也是apollo背后的团队,技术水平是值得信赖的。

支持npm,可以整合其他框架,例如expressjs

Meteor之前是仅通过Atmosphere来扩展,后来开始直接支持npm,这样一来,其他nodejs框架可以直接整合,例如meteor没有官方支持的restapi方式,可通过整合express来实现,这样meteor完全融合到了nodejs生态中。 整合express的示例

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

import bodyParser from 'body-parser';

export function setupApi() {
  const app = express();

  app.use(bodyParser.json()); // for parsing application/json
  app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

  var t1 = require('./t1');
  var t2 = require('./t2');

  app.use('/t1', t1);
  app.use('/t2', t2);

  WebApp.connectHandlers.use(app);
}

其中用到的是meteor webapp api

atmospherejs示例
meteor add qualia:reval
会在.meteor/pacakge中增加对应信息,且代码中不需要显示import

npm方式
meteor npm i exressjs
会在pacakge.json中添加信息
不要尝试npm i xx直接添加,因为meteor工具自带绑定版本的node和npmj

web前端官方支持react,Angular

对于meteor自带的Blaze,由于其提供了许多便利的特性,一般建议与React,Angular合用

移动端支持

使用Cordova,

使用DDP方式调用meteor服务端

缺点

仍算比较冷门,中文支持较少

与普通的nodejs开发方式不太相同,学习曲线稍陡

默认绑定了mongodb

这可以说是个优点,如果你本来就用mongo,然而大部分情况我会认为是个缺点,虽然可以使用其他数据库整合,但mongodb是必须的,你可以不用它,但是这样会丢失DDP很多特性,且必须通过MONGO_URL配置启动。

它可以横向扩展(scale out),但是不是那么简单

meteor圈如果有人问怎么横向扩展,往往得到的回答是类似-先让你的应用达到需要扩展的用户数量再说吧,那时候不管怎么样都是时候重构了。(It helps that we’re not planning at building apps targeted at millions of users, but when you hit that kind of scale, refactoring is anyway going to happen.)

这个回答确实很实际,就像RoR作者DHH说的”在选彩票的时候就开始操心中奖以后买哪个游艇。”(Programmers worrying about whether their architecture will Web Scale is like buying a lottery coupon and fretting about which yacht to buy.)

如果不用mongo,那你就不能使用mongo oplog来scale out.这种情况如果要使用publications,就必须使用服务端local collection,本质上是一种不支持集群的内存数据库,那么就做不到scale out。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容