Meteor介紹

本文轉(zhuǎn)自我的博客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是一個(gè)full-stack javascript平臺(tái),可用于開發(fā)web和移動(dòng)應(yīng)用。其最大特點(diǎn)是其(通過websocket)保持客戶端連接的“實(shí)時(shí)”框架滔灶。數(shù)據(jù)庫(mongodb)的改變可“實(shí)時(shí)”展示到界面中瑞眼。

以下列出優(yōu)缺點(diǎn)更直觀的了解meteor夺英。

優(yōu)點(diǎn)

實(shí)時(shí)

讀取數(shù)據(jù)使用DDP

數(shù)據(jù)實(shí)時(shí)讀取使用DDP(distributed data protocal)的pub/sub明垢,一般是websocket實(shí)現(xiàn)的的pub/sub方式神得。

例如不停的請(qǐng)求第三方api來達(dá)到實(shí)時(shí)效果官方示例

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方法來實(shí)現(xiàn)數(shù)據(jù)publish, 這種方式有個(gè)問題奈籽,即沒有通過mongodb饥侵,創(chuàng)建的是其實(shí)是local collection,那么它的改變只對(duì)當(dāng)前連接(websocket)有效,無法做到多個(gè)clients共享衣屏。其實(shí)相當(dāng)于為每個(gè)subscribe客戶端創(chuàng)建一個(gè)同名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
  });
});

首先需要明確,不管服務(wù)端數(shù)據(jù)源是否來自mongodb,客戶端都有一個(gè)內(nèi)存mongodb,客戶端都是針對(duì)這個(gè)mongodb來查詢操作狼忱。 詳見這里

再來看看默認(rèn)的基于服務(wù)端Mongodb數(shù)據(jù)實(shí)現(xiàn):
使用的是MongoDB’s Oplog,對(duì)mongo數(shù)據(jù)庫的修改得以立即廣播到讀取指針(cursor).
示例

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

魔法就在于Lists.find膨疏,如果對(duì)應(yīng)的集合有所變動(dòng)一睁,都會(huì)向客戶端廣播。
oplog也有一些限制 最主要的是佃却,mongodb必須是replica set,否則還是默認(rèn)的polling者吁。這一下子就提高了門檻。 不過饲帅,polling對(duì)于同一個(gè)進(jìn)程的修改反映還是蠻快的复凳,而默認(rèn)的meteor collection實(shí)現(xiàn)應(yīng)該是一個(gè)進(jìn)程中,故還不錯(cuò)灶泵。目前meteor1.7的版本使用的是mogon 3.0的driver育八,還不能使用driver3.1事務(wù),如果自己新開一個(gè)cmongo client,則估計(jì)是在另外一個(gè)process,從測(cè)試結(jié)果來看,與meteor的collection更新時(shí)間間隔有5秒以上的差距赦邻,見示例.

修改數(shù)據(jù)使用method(也屬于DDP協(xié)議)

method類似RPC髓棋; method有一些特點(diǎn):

  • 客戶端調(diào)用方法直接引用定義文件調(diào)用,直觀惶洲。
  • 現(xiàn)在客戶端調(diào)用驗(yàn)證按声,如果失敗,就不會(huì)調(diào)用服務(wù)端恬吕。
  • 方便于測(cè)試签则。
不提倡從method獲得數(shù)據(jù)

一般應(yīng)該是從pub/sub獲得數(shù)據(jù),method只負(fù)責(zé)修改币呵,不應(yīng)該從method的返回獲得數(shù)據(jù)。因?yàn)殡m然method是能夠返回?cái)?shù)據(jù)的侨颈, 但這種情況下余赢,你還得手動(dòng)維護(hù)客戶端mongodb的數(shù)據(jù)一致性。

// 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相對(duì)于REST API的好處

基于Fibers,編寫類似于同步方式的代碼哈垢,但是不是阻塞(blocking)的

使用fibers將method(請(qǐng)求估計(jì)也是websocket妻柒,由于每個(gè)method都有id,將調(diào)用和返回通過id關(guān)聯(lián)耘分,將websocket異步的包裝成同步的)封裝成同步的形式举塔,這樣既保持了websocket的便利,也使得編碼邏輯直觀求泰。 Fiber不是個(gè)新概念央渣,它不同于thread,并不能起到thread的作用渴频,個(gè)人理解芽丹,更像nodejs里面await/async的一種實(shí)現(xiàn)。 例如meteor里的method需要返回卜朗,是不支持callback的方式的拔第,可以通過Meteor.wrapAsync來包裝callback方式的調(diào)用咕村。
舉個(gè)例子

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;
      }
    }

請(qǐng)求和返回都是有序的

對(duì)于ajax請(qǐng)求,請(qǐng)求和返回不能保證有序蚊俺,可能后請(qǐng)求的先得到返回懈涛。meteor保證了每個(gè)客戶端的每個(gè)請(qǐng)求都是有序的,前一個(gè)調(diào)用成功后才進(jìn)行下一個(gè)泳猬。不過對(duì)于特殊的情況批钠,也可以改變這個(gè)機(jī)制而使得執(zhí)行無序。例如this.unblock()暂殖。

每個(gè)DDP(pub/sub和method)都可以是綁定用戶信息的

通過this.userId可用于判斷用戶是否登錄价匠,用戶系統(tǒng)可自定義,也可使用meteor的api呛每。

商業(yè)支持踩窖,論壇支持,文檔詳細(xì)

meteor雖然開源,但背后有專門的商業(yè)公司支持,目前來看github上有40k+星標(biāo)晨横,項(xiàng)目活躍程度還算不錯(cuò) 其提供hosting服務(wù)洋腮,也提供商業(yè)支持服務(wù),商業(yè)支持服務(wù)對(duì)于商業(yè)項(xiàng)目來說是很重要的考慮點(diǎn)手形。

meteor背后的團(tuán)隊(duì)是Meteor Development Group(MDG),也是apollo背后的團(tuán)隊(duì)啥供,技術(shù)水平是值得信賴的。

支持npm库糠,可以整合其他框架伙狐,例如expressjs

Meteor之前是僅通過Atmosphere來擴(kuò)展,后來開始直接支持npm瞬欧,這樣一來贷屎,其他nodejs框架可以直接整合,例如meteor沒有官方支持的restapi方式艘虎,可通過整合express來實(shí)現(xiàn)唉侄,這樣meteor完全融合到了nodejs生態(tài)中。 整合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
會(huì)在.meteor/pacakge中增加對(duì)應(yīng)信息野建,且代碼中不需要顯示import

npm方式
meteor npm i exressjs
會(huì)在pacakge.json中添加信息
不要嘗試npm i xx直接添加属划,因?yàn)閙eteor工具自帶綁定版本的node和npmj

web前端官方支持react,Angular

對(duì)于meteor自帶的Blaze,由于其提供了許多便利的特性,一般建議與React,Angular合用

移動(dòng)端支持

使用Cordova,

使用DDP方式調(diào)用meteor服務(wù)端

缺點(diǎn)

仍算比較冷門嗽测,中文支持較少

與普通的nodejs開發(fā)方式不太相同,學(xué)習(xí)曲線稍陡

默認(rèn)綁定了mongodb

這可以說是個(gè)優(yōu)點(diǎn),如果你本來就用mongo,然而大部分情況我會(huì)認(rèn)為是個(gè)缺點(diǎn)唠粥,雖然可以使用其他數(shù)據(jù)庫整合疏魏,但mongodb是必須的,你可以不用它晤愧,但是這樣會(huì)丟失DDP很多特性,且必須通過MONGO_URL配置啟動(dòng)大莫。

它可以橫向擴(kuò)展(scale out),但是不是那么簡(jiǎn)單

meteor圈如果有人問怎么橫向擴(kuò)展,往往得到的回答是類似-先讓你的應(yīng)用達(dá)到需要擴(kuò)展的用戶數(shù)量再說吧官份,那時(shí)候不管怎么樣都是時(shí)候重構(gòu)了只厘。(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.)

這個(gè)回答確實(shí)很實(shí)際,就像RoR作者DHH說的”在選彩票的時(shí)候就開始操心中獎(jiǎng)以后買哪個(gè)游艇舅巷「嵛叮”(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,就必須使用服務(wù)端local collection,本質(zhì)上是一種不支持集群的內(nèi)存數(shù)據(jù)庫,那么就做不到scale out钠右。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赋元,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子飒房,更是在濱河造成了極大的恐慌搁凸,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狠毯,死亡現(xiàn)場(chǎng)離奇詭異护糖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嚼松,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門嫡良,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人献酗,你說我怎么就攤上這事寝受。” “怎么了凌摄?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵羡蛾,是天一觀的道長(zhǎng)漓帅。 經(jīng)常有香客問我锨亏,道長(zhǎng),這世上最難降的妖魔是什么忙干? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任器予,我火速辦了婚禮,結(jié)果婚禮上捐迫,老公的妹妹穿的比我還像新娘乾翔。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布反浓。 她就那樣靜靜地躺著萌丈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雷则。 梳的紋絲不亂的頭發(fā)上辆雾,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音月劈,去河邊找鬼度迂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛猜揪,可吹牛的內(nèi)容都是我干的惭墓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼而姐,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼腊凶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起毅人,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤吭狡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后丈莺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體划煮,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年缔俄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弛秋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俐载,死狀恐怖蟹略,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情遏佣,我是刑警寧澤挖炬,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站状婶,受9級(jí)特大地震影響意敛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜膛虫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一草姻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧稍刀,春花似錦撩独、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澳迫。三九已至,卻和暖如春剧劝,著一層夾襖步出監(jiān)牢的瞬間纲刀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工担平, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留示绊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓暂论,卻偏偏與公主長(zhǎng)得像面褐,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子取胎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容