成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

微型庫(kù)解讀之200byte的EventEmitter - Mitt

fredshare / 1727人閱讀

摘要:微型庫(kù)解讀之的前端起源關(guān)于我想應(yīng)該很多同學(xué)都很熟悉了。小而美的整個(gè)庫(kù)非常的小,但是卻功能齊全,為了縮減代碼,也是有一些小技巧在里面。這幾天也在瘋狂的看寫(xiě)的一些庫(kù),他的庫(kù)都有小而美的特點(diǎn),無(wú)論是著名的還是簡(jiǎn)單的這種庫(kù)。

title: 微型庫(kù)解讀之200byte的EventEmitter - Mitt
tags: 前端

date: 2018-01-26 00:55:08 起源

關(guān)于 EventEmitter 我想應(yīng)該很多同學(xué)都很熟悉了。簡(jiǎn)而言之是一個(gè)事件的發(fā)布與訂閱器。
這兩天讀到了一些非常有意思的小庫(kù),雖然小但是功能完備,比如說(shuō)這次我們要講解的 Mitt.

Github地址

Mitt是一個(gè)微型的 EventEmitter 庫(kù),實(shí)現(xiàn)了基本的 on, off, emit 三個(gè)Api,對(duì)于使用 EventEmitter 其他功能不多的同學(xué)來(lái)說(shuō),200byte 的體積可以說(shuō)是非常劃算了。

當(dāng)然小也有其付出的代價(jià),那就是只支持這三個(gè)功能。
至于怎么取舍,見(jiàn)仁見(jiàn)智吧,我建議是先使用 mitt,就算后期要更換別的庫(kù),因?yàn)?Api 統(tǒng)一,所以更換起來(lái)基本不費(fèi)事。

Mitt 在 Github的 demo 中,也顯示出了代碼雖小,五臟俱全的特點(diǎn)。

Demo:

import mitt from "mitt"

let emitter = mitt()

// listen to an event
emitter.on("foo", e => console.log("foo", e) )

// listen to all events
emitter.on("*", (type, e) => console.log(type, e) )

// fire an event
emitter.emit("foo", { a: "b" })

// working with handler references:
function onFoo() {}
emitter.on("foo", onFoo)   // listen
emitter.off("foo", onFoo)  // unlisten
代碼解讀

在研究 Mitt 能完成的功能后,也在想為什么能做到這么小。
在這兒對(duì)一些閃光點(diǎn)做一些解讀。

節(jié)約內(nèi)存且避免沖突的 EventMap
export default function mitt(all: EventHandlerMap) {
    all = all || Object.create(null);
    return {
      // ...Api
    }
}

在初始化 mitt 時(shí),會(huì)有一個(gè)可選的參數(shù) all,用于存放要監(jiān)聽(tīng)的事件。
如果初始化不傳參時(shí),會(huì)使用 Object.create(null) 來(lái)實(shí)現(xiàn)。
這樣的好處在于,生成的對(duì)象是一個(gè)原型為空的對(duì)象。

優(yōu)點(diǎn)如下:

節(jié)約內(nèi)存

避免沖突

節(jié)約內(nèi)存是因?yàn)闆](méi)有了原型,可以節(jié)省部分開(kāi)銷。
避免沖突則是因?yàn)樵谄胀▽?duì)象中,當(dāng)要觸發(fā)的事件與對(duì)象原型上的屬性或方法重名時(shí),會(huì)出現(xiàn)事件不存在卻被錯(cuò)誤觸發(fā)導(dǎo)致不必要的問(wèn)題。

var obj = {};
console.log("toString" in obj);

var noPrototypeObj = Object.create(null);
console.log("toString" in noPrototypeObj);

輸出結(jié)果如下:

簡(jiǎn)潔的隊(duì)列初始化

經(jīng)常我們會(huì)做這樣一個(gè)操作,當(dāng)對(duì)象中某個(gè)屬性不存在時(shí),就初始化,存在則直接返回值。用代碼表示就是:

var obj = {};

var getQueue = (key) => {
  if (!obj[key]) {
    obj[key] = []
  }

  return obj[key]
}

這是一個(gè)很常見(jiàn)的操作,但是在 mitt 的卻簡(jiǎn)潔了很多。

export default function mitt(all: EventHandlerMap) {
    all = all || Object.create(null);

    return {
        /**
         * Register an event handler for the given type.
         *
         * @param  {String} type    Type of event to listen for, or `"*"` for all events
         * @param  {Function} handler Function to call in response to given event
         * @memberOf mitt
         */
        on(type: string, handler: EventHandler) {
            (all[type] || (all[type] = [])).push(handler);
        }
    };
}

on 函數(shù)之中,有這么一句:(all[type] || (all[type] = []))
這個(gè)表達(dá)式的意思很簡(jiǎn)單,有值取值,無(wú)值初始化。

但是總的代碼量比起之前的代碼小了很多,實(shí)現(xiàn)了簡(jiǎn)化代碼的目的。

PS:這個(gè)操作我之前在讀 React setState 源代碼時(shí),也碰到過(guò)。

其中 queue 的獲取便是使用了這種方式。

無(wú)符號(hào)右移(>>>)

off 的Api中,有使用到無(wú)符號(hào)右移(>>>)的操作,具體操作如下:

/**
 * Remove an event handler for the given type.
 *
 * @param  {String} type    Type of event to unregister `handler` from, or `"*"`
 * @param  {Function} handler Handler function to remove
 * @memberOf mitt
 */
off(type: string, handler: EventHandler) {
    if (all[type]) {
        all[type].splice(all[type].indexOf(handler) >>> 0, 1);
    }
}

其中 all[type].splice(all[type].indexOf(handler) >>> 0, 1); 這一句的作用可謂亮眼。
移除某個(gè)指定的事件監(jiān)聽(tīng)是很正常的事,但可能會(huì)有一個(gè)問(wèn)題,就是傳入的要移除的監(jiān)聽(tīng)器并不存在。
換做以往的代碼,可能你會(huì)先搜索,再?zèng)Q定是否執(zhí)行移除操作,但是這樣一來(lái)代碼量就又增加了。

而無(wú)符號(hào)右移(>>>),恰恰符合我們的需要。

具體的作用如 demo,在搜索的事件監(jiān)聽(tīng)函數(shù)不存在時(shí),會(huì)返回一個(gè)極大的正數(shù),傳入 splice 后,并不會(huì)刪除已有的函數(shù)監(jiān)聽(tīng)器,從而實(shí)現(xiàn)了想要的功能。

監(jiān)聽(tīng)所有事件的監(jiān)聽(tīng)器

在日常開(kāi)發(fā)中,經(jīng)常可能想監(jiān)聽(tīng)所有的事件,來(lái)輔助開(kāi)發(fā)。
mitt 就實(shí)現(xiàn)了這個(gè)功能。

Demo:

import mitt from "mitt"
let emitter = mitt()
// listen to all events
emitter.on("*", (type, e) => console.log(type, e) )

而在源代碼里,這個(gè)的實(shí)現(xiàn)很簡(jiǎn)潔:

/**
 * Invoke all handlers for the given type.
 * If present, `"*"` handlers are invoked after type-matched handlers.
 *
 * @param {String} type  The event type to invoke
 * @param {Any} [evt]  Any value (object is recommended and powerful), passed to each handler
 * @memberOf mitt
 */
emit(type: string, evt: any) {
    (all[type] || []).slice().map((handler) => { handler(evt); });
    (all["*"] || []).slice().map((handler) => { handler(type, evt); });
}

就是在使用 emit 函數(shù)時(shí),找出事件類型為 * 的監(jiān)聽(tīng)器,并觸發(fā)它。

小而美

Mitt的整個(gè)庫(kù)非常的小,但是卻功能齊全,為了縮減代碼,也是有一些小技巧在里面。
但是 Mitt的庫(kù)小也有缺點(diǎn),比如參數(shù)的類型如果傳錯(cuò)了,它并不會(huì)預(yù)先提示你,這也算是一個(gè)要取舍的點(diǎn)吧。

這幾天也在瘋狂的看 developit 寫(xiě)的一些庫(kù),他的庫(kù)都有小而美的特點(diǎn),無(wú)論是著名的 Preact 還是簡(jiǎn)單的 mitt 這種庫(kù)。他寫(xiě)的代碼,還是挺值得一讀的。

計(jì)劃

之后的計(jì)劃,可能也準(zhǔn)備寫(xiě)幾篇這種微型庫(kù)的源碼閱讀文章,這種庫(kù)讀起來(lái)輕松,適合每天讀一兩個(gè),而能學(xué)到的東西和思路也不少。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92794.html

相關(guān)文章

  • Source Code - JavaScript - 學(xué)習(xí)優(yōu)雅編碼

    摘要:以下全是別人的源碼,會(huì)標(biāo)明出處,非常感謝原作者,非常感謝開(kāi)源。優(yōu)雅源碼,微型庫(kù)解讀之的源碼零散短路運(yùn)算符詳情生成的對(duì)象是一個(gè)原型為空的對(duì)象。簡(jiǎn)潔的隊(duì)列賦值短路邏輯判斷初始化更新數(shù)組,簡(jiǎn)直不要太優(yōu)雅。 寧?kù)o致遠(yuǎn)。 說(shuō)明 知識(shí)在不斷迭代,除了學(xué)習(xí)資料,那就是學(xué)習(xí)他人,來(lái)豐富自己。 以下全是別人的源碼,會(huì)標(biāo)明出處,非常感謝原作者,非常感謝開(kāi)源。 優(yōu)雅 mitt:源碼,微型庫(kù)解讀之20...

    zhoutk 評(píng)論0 收藏0
  • 回首2017: 你其實(shí)是一個(gè)收集貝殼孩子

    摘要:我卻這樣認(rèn)為我好像是在海上玩耍,時(shí)而發(fā)現(xiàn)了一個(gè)光滑的石子兒,時(shí)而發(fā)現(xiàn)一個(gè)美麗的貝殼而為之高興的孩子。在年底之前,挑一些精致美麗的貝殼,分享出來(lái)。這是快速,易于使用,讓您擔(dān)心比建立一個(gè)文件上傳更重要的問(wèn)題。 showImg(https://segmentfault.com/img/remote/1460000012622184?w=800&h=534); 我不知道世上的人對(duì)我怎樣評(píng)價(jià)。我...

    wslongchen 評(píng)論0 收藏0
  • Node.js - 200 多行代碼實(shí)現(xiàn) Websocket 協(xié)議

    摘要:預(yù)備工作序最近正在研究相關(guān)的知識(shí),想著如何能自己實(shí)現(xiàn)協(xié)議。監(jiān)聽(tīng)事件就是協(xié)議的抽象,直接在上面監(jiān)聽(tīng)已有的事件和事件這兩個(gè)事件。表示當(dāng)前數(shù)據(jù)幀為消息的最后一個(gè)數(shù)據(jù)幀,此時(shí)接收方已經(jīng)收到完整的消息,可以對(duì)消息進(jìn)行處理。 A、預(yù)備工作 1、序 最近正在研究 Websocket 相關(guān)的知識(shí),想著如何能自己實(shí)現(xiàn) Websocket 協(xié)議。到網(wǎng)上搜羅了一番資料后用 Node.js 實(shí)現(xiàn)該協(xié)議,倒也沒(méi)...

    張巨偉 評(píng)論0 收藏0
  • Node 錯(cuò)誤處理挖坑系列

    摘要:一中的對(duì)象包含了錯(cuò)誤的具體信息,包括錯(cuò)誤堆棧等。不源碼了,特別簡(jiǎn)單,自己去一下。 一. Error ????JS 中的 Error 對(duì)象. 包含了錯(cuò)誤的具體信息,包括 name、message、錯(cuò)誤堆棧 stack 等??梢砸?new Error 方式創(chuàng)建實(shí)例拋出,或調(diào)用 Error.captureStackTrace 為已有對(duì)象添加 stack 錯(cuò)誤堆棧信息 而后拋出showImg(...

    afishhhhh 評(píng)論0 收藏0
  • node.js入門學(xué)習(xí)筆記整理——基礎(chǔ)篇

    摘要:的介紹一般是這樣在中,類是隨內(nèi)核一起發(fā)布的核心庫(kù)。庫(kù)為帶來(lái)了一種存儲(chǔ)原始數(shù)據(jù)的方法,可以讓處理二進(jìn)制數(shù)據(jù),每當(dāng)需要在中處理操作中移動(dòng)的數(shù)據(jù)時(shí),就有可能使用庫(kù)。這樣傳遞數(shù)據(jù)會(huì)更快。 零、開(kāi)始之前 1、 首先解釋一下node.js是什么? 2、node.js和javascript有什么不同? 1)因?yàn)閖avascript主要是用在browser,而node.js是在server或者你的電腦...

    Tamic 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

fredshare

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<