https://github.com/MetaMask/obs-store

ObservableStore

ObservableStore is a synchronous in-memory store for a single value, that you can subscribe to updates on

ObservableStore是一个内存中的可以订阅更新的同步存储,只存储一个值

const store = new ObservableStore(initState)
store.subscribe(function showValue(value) {
console.log('saw value:', value)
})

//通过调用putState()来存储值
store.putState() // "saw value: 5" ,存储了5
store.putState(true) // "saw value: true" ,true覆盖了之前的5的值
store.putState({ hello: 'world' }) // "saw value: { hello: 'world' }" ,{ hello: 'world' }覆盖了之前的true的值 console.log(store.getState().hello) // "world" ,通过调用getState()函数来得到存储的值
从上面的例子可以看出能且只能够存储一个值

streams

Each ObservableStore can be turned into an ObservableStoreStream. An ObservableStoreStream is a duplex stream that you can pipe new values into it or pipe its updated values out of it.

ObservableStore可以转换成ObservableStoreStream流,并且是一个双工流

Special behavior: Doesnt buffer outgoing updates, writes latest state to dest on pipe.

不缓冲输出更新,将最新状态写到管道dest上

const pipe = require('pump')
const asStream = require('obs-store/lib/asStream') const storeOne = new ObservableStore(initState)
const storeTwo = new ObservableStore() pipe(//相当于asStream(storeOne).pipe(transformStream).pipe(asStream(storeTwo)),而且使用pump监听错误
asStream(storeOne),
transformStream,
asStream(storeTwo)
)

Changelog

3.0.0

ObservableStore are no longer streams. You can create streams via asStream.

通过asStream来创建ObservableStoreStream

obs-store/index.js

'use strict'

const extend = require('xtend')
const EventEmitter = require('events') class ObservableStore extends EventEmitter { constructor (initState = {}) {
super()
// set init state
this._state = initState
} // wrapper around internal getState
getState () {//输出值
return this._getState()
} // wrapper around internal putState
putState (newState) {
this._putState(newState)//存储newState值
this.emit('update', newState)//并触发subscribe中的'update'事件,并调用相应的handler函数
} updateState (partialState) {//更改里面的一部分的值
// if non-null object, merge
if (partialState && typeof partialState === 'object') {
const state = this.getState()
const newState = Object.assign({}, state, partialState)
this.putState(newState)
// if not object, use new value
} else {
this.putState(partialState)
}
} // subscribe to changes
subscribe (handler) {
this.on('update', handler)
} // unsubscribe to changes
unsubscribe (handler) {
this.removeListener('update', handler)//移除'update'事件
} //
// private
// // read from persistence
_getState () {
return this._state
} // write to persistence
_putState (newState) {
this._state = newState
} } module.exports = ObservableStore

其调用的lib库:

obs-store/lib/asStream.js

作用是将ObsStore转成ObsStoreStream流,并定义流相应的一些方法

const DuplexStream = require('stream').Duplex

module.exports = asStream

function asStream(obsStore) {
return new ObsStoreStream(obsStore)
} //
//
//
// class ObsStoreStream extends DuplexStream { constructor(obsStore) {
super({
// pass values, not serializations
objectMode: true,
})
// dont buffer outgoing updates
this.resume()
// save handler so we can unsubscribe later
this.handler = (state) => this.push(state)
// subscribe to obsStore changes
this.obsStore = obsStore
this.obsStore.subscribe(this.handler)
} // emit current state on new destination
pipe (dest, options) {//调用pipe函数,将obsStore.getState()值传到dest
const result = DuplexStream.prototype.pipe.call(this, dest, options)
dest.write(this.obsStore.getState())
return result
} // write from incomming stream to state
_write (chunk, encoding, callback) {
this.obsStore.putState(chunk)
callback()
} // noop - outgoing stream is asking us if we have data we arent giving it
_read (size) { } // unsubscribe from event emitter
_destroy (err, callback) {
this.obsStore.unsubscribe(this.handler);
super._destroy(err, callback)
} }

obs-store/lib/localStorage.js

设置一个继承ObservableStore的LocalStorageStore,页面端的global.localStorage就是这个

'use strict'

const ObservableStore = require('../')

class LocalStorageStore extends ObservableStore {

  constructor (opts = {}) {
if (!global.localStorage) throw new Error('LocalStorageStore - can\'t find localStorage.')//global.localStorage即浏览器本身是否有本地存储
super()
this._storageKey = opts.storageKey
if (!this._storageKey) throw new Error('LocalStorageStore - no storageKey specified.')
} //
// private
// // read from persistence
_getState () {
const serialized = global.localStorage.getItem(this._storageKey)//不同的_storageKey对应的是本地存储的不同内容
return serialized ? JSON.parse(serialized) : undefined
} // write to persistence
_putState (newState) {
const serialized = JSON.stringify(newState)
return global.localStorage.setItem(this._storageKey, serialized)
} } module.exports = LocalStorageStore

还有一些别的,但是先不管,之后用到再说

测试:

'use strict'

const test = require('tape')const pipe = streamUtils.pipeconst ObservableStore = require('../')
const asStream = require('../lib/asStream') const TEST_WAIT = test('basic stream', function(t){
t.plan() const initState = 'init'
const nextState = 'next' const storeOne = new ObservableStore(initState)//在初始化时就存储值initState
const storeTwo = new ObservableStore()//在初始化时并没有存储值
storeTwo.once('update', (value) => {//监听一次'update'事件
initValueCheck(value)//查看value值与initState值是否相同
storeTwo.once('update', nextValueCheck)//再监听一次查看与nextState的值是否相同
}) pipe(//将storeOne流中的值initState传给storeTwo流,storeTwo调用putState时会调用一次'update'事件,查看是否于initState值相同
asStream(storeOne),
asStream(storeTwo)
) storeOne.putState(nextState)//将storeOne中的值从initState改变成nextState,这里又会触发一次'update'事件,这次是查看是否于nextState相同 function initValueCheck(value){
t.equal(value, initState, 'storeTwo subscribed: state is initState')
} function nextValueCheck(value){
t.equal(value, nextState, 'storeTwo subscribed: state is nextState')
} }) test('double stream', function(t){
t.plan() const initState = 'init'
const nextState = 'next' const storeOne = new ObservableStore(initState)
const storeTwo = new ObservableStore()
storeTwo.once('update', (initValue) => {
initValueCheck('storeTwo', initValue)
storeTwo.once('update', (nextValue) => nextValueCheck('storeTwo', nextValue))
}) const storeThree = new ObservableStore()
storeThree.once('update', (initValue) => {
initValueCheck('storeThree', initValue)
storeThree.once('update', (nextValue) => nextValueCheck('storeThree', nextValue))
}) pipe(
asStream(storeOne),
asStream(storeTwo)//storeTwo触发一次'update'
) pipe(
asStream(storeOne),
asStream(storeThree)//storeThree触发一次'update'
) storeOne.putState(nextState)//将会导致storeTwo、storeThree再分别触发一次 function initValueCheck(label, value){
t.equal(value, initState, `${label} subscribed: state is initState`)
} function nextValueCheck(label, value){
t.equal(value, nextState, `${label} subscribed: state is nextState`)
} })

LocalStorageStore的测试,首先localStorage是定义好的,并且是有storageKey值的,如{ storageKey: 'test' }

'use strict'

const test = require('tape')
const LocalStorageStore = require('../lib/localStorage') test('localStorage - localStorage presence validation', function(t){
t.plan() t.notOk(global.localStorage, 'global.localStorage not defined') t.throws(() => {
new LocalStorageStore({ storageKey: 'test' })
}, Error, 'throws error when localStorage is not defined') }) test('localStorage - storageKey validation', function(t){
t.plan() global.localStorage = createLocalStorage() t.ok(global.localStorage, 'global.localStorage is defined') t.throws(() => {
new LocalStorageStore()
}, Error, 'throws error when opts.storageKey is not defined') }) test('localStorage - basic test', function(t){
t.plan() global.localStorage = createLocalStorage() t.ok(global.localStorage, 'global.localStorage is defined') const store = new LocalStorageStore({ storageKey: 'test' })
store.putState() t.equal(store.getState(), , 'store works roundtrips values great')
}) test('localStorage - obj test', function(t){
t.plan() global.localStorage = createLocalStorage() t.ok(global.localStorage, 'global.localStorage is defined') const store = new LocalStorageStore({ storageKey: 'test' })
store.putState({ a: }) t.deepEqual(store.getState(), { a: }, 'store works roundtrips obj values great')
}) function createLocalStorage() {
const values = {}
const localStorage = {}
localStorage.getItem = (key) => values[key]
localStorage.setItem = (key, value) => values[key] = value
return localStorage
}

MetaMask/obs-store的更多相关文章

  1. OBS源码解析(3)OBSApp类介绍

    OBSApp类有以下功能: 1.负责配置文件管理 2.版本信息管理 3.主界面OBSBasic对象管理 4.obs模块初始化 class OBSApp : public QApplication { ...

  2. metamask源码学习-controller-transaction

    ()metamask-extension/app/scripts/controllers/transactions Transaction Controller is an aggregate of ...

  3. metamask源码学习-background.js

    这个就是浏览器后台所进行操作的地方了,它就是页面也区块链进行交互的中间部分. metamask-background描述了为web扩展单例的文件app/scripts/background.js.该上 ...

  4. metamask源码学习-metamask-controller.js

    The MetaMask Controller——The central metamask controller. Aggregates other controllers and exports a ...

  5. Guide to Porting MetaMask to a New Environment

    https://github.com/MetaMask/metamask-extension/blob/develop/docs/porting_to_new_environment.md MetaM ...

  6. metamask源码学习-ui/index.js

    The UI-即上图左下角metamask-ui部分,即其图形化界面 The MetaMask UI is essentially just a website that can be configu ...

  7. metamask源码学习-controllers-network

    https://github.com/MetaMask/metamask-extension/tree/master/app/scripts/controllers/network metamask- ...

  8. MetaMask/metamask-extension-provider

    用来探测你的浏览器中有没有安装metamask插件 https://github.com/MetaMask/metamask-extension-provider MetaMask Extension ...

  9. mac obs直播软件 无法输出音频解决办法

    搜索大量的网页,确没有一个实用的设置教程,也正是speechless. 直接做个教程,方便大家的使用 1.安装 boom 2 到app store 上搜索boom 我安装的是正版的,需要128元. 你 ...

随机推荐

  1. Linux中ansible批量管理软件部署及剧本编写

    服务器版本信息: Centos6.9 [root@db02 ~]# uname -a Linux db02 2.6.32-696.el6.x86_64 #1 SMP Tue Mar 21 19:29: ...

  2. c# 数组协变

    class a{} class b:a{} a[] arr=new a[3]; a[] arr2=new a[3]; 给arr 数组赋值 arr[0]=new a(); arr2[0]=new b() ...

  3. IIS服务器SSL证书安装

    在证书控制台下载IIS版本证书,下载到本地的是一个压缩文件,解压后里面包含.pfx文件是证书文件,pfx_password.txt是证书文件的密码. 友情提示: 每次下载都会产生新密码,该密码仅匹配本 ...

  4. hadoop 集群中数据块的副本存放策略

    HDFS采用一种称为机架感知(rack-aware)的策略来改进数据的可靠性.可用性和网络带宽的利用率.目前实现的副本存放策略只是在这个方向上的第一步.实现这个策略的短期目标是验证它在生产环境下的有效 ...

  5. 【Java并发编程】22、Exchanger源码解析(JDK1.7)

    Exchanger是双向的数据传输,2个线程在一个同步点,交换数据.先到的线程会等待第二个线程执行exchangeSynchronousQueue,是2个线程之间单向的数据传输,一个put,一个tak ...

  6. 最长子串(FZU2128)

    最长子串 Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status  ...

  7. 【读书笔记】iOS-设计模式

    一个可复用的解决方案,用于处理特定场景下的常见问题.一种设计模式并不是一个可以直接转化为代码的已完工设计.它是对于如何解决问题的一种描述或者模板,可以用在许多不同的场合. 参考资料:<iOS W ...

  8. Kafka初入门简单配置与使用

    一 Kafka概述 1.1 Kafka是什么 在流式计算中,Kafka一般用来缓存数据,Storm通过消费Kafka的数据进行计算. 1)Apache Kafka是一个开源消息系统,由Scala写成. ...

  9. (后台)There is already 'jy.controller.jyadmin.JyDealerPackingReturnController' bean method

    项目报了一个错误,百度翻译了一下: “我已经有jy.controller.jyadmin.jydealerpackingreturncontroller豆方法公共org.springframework ...

  10. JavaScript大杂烩13 - 总结ECMAScript 5新功能

    虽说这个标准已经出来很久了,所有的主流浏览器的最新版本也都支持了这些特性,但是很多的教程中并没有包含这个部分,这一节我们专门来总结一下这个标准中的新功能. Object的新方法 在最新的JavaScr ...