MetaMask/obs-store
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库:
作用是将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)
}
}
设置一个继承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的更多相关文章
- OBS源码解析(3)OBSApp类介绍
OBSApp类有以下功能: 1.负责配置文件管理 2.版本信息管理 3.主界面OBSBasic对象管理 4.obs模块初始化 class OBSApp : public QApplication { ...
- metamask源码学习-controller-transaction
()metamask-extension/app/scripts/controllers/transactions Transaction Controller is an aggregate of ...
- metamask源码学习-background.js
这个就是浏览器后台所进行操作的地方了,它就是页面也区块链进行交互的中间部分. metamask-background描述了为web扩展单例的文件app/scripts/background.js.该上 ...
- metamask源码学习-metamask-controller.js
The MetaMask Controller——The central metamask controller. Aggregates other controllers and exports a ...
- Guide to Porting MetaMask to a New Environment
https://github.com/MetaMask/metamask-extension/blob/develop/docs/porting_to_new_environment.md MetaM ...
- metamask源码学习-ui/index.js
The UI-即上图左下角metamask-ui部分,即其图形化界面 The MetaMask UI is essentially just a website that can be configu ...
- metamask源码学习-controllers-network
https://github.com/MetaMask/metamask-extension/tree/master/app/scripts/controllers/network metamask- ...
- MetaMask/metamask-extension-provider
用来探测你的浏览器中有没有安装metamask插件 https://github.com/MetaMask/metamask-extension-provider MetaMask Extension ...
- mac obs直播软件 无法输出音频解决办法
搜索大量的网页,确没有一个实用的设置教程,也正是speechless. 直接做个教程,方便大家的使用 1.安装 boom 2 到app store 上搜索boom 我安装的是正版的,需要128元. 你 ...
随机推荐
- 程序员快速掌握的UI设计技巧
一.概要 功能与内在很关键,UI与外表也重要. 1.1.选择主色调 1.1.1.三原色 三原色指色彩中不能再分解的三种基本颜色,我们通常说的三原色,即红.黄.蓝.三原色可以混合出所有的颜色,同时相加为 ...
- 修改Mysql字符集
第一种 一.修改my.ini配置文件(MySQL配置文件) character_set_server = utf8 #设置字符集 重启mysql数据库服务 查看当前数据库字符集 show VARIAB ...
- IDEA创建简单SSM项目使用传统Jar包
#IDEA SSM项目使用传统Jar包 创建项目 下一步,命名 下一步,创建完成 下一步,创建资源文件夹resources 页面概览 左侧目录树 演示如下 一些简单的说明 其中包之间的层次调用 ent ...
- JS之this应用详解
目录 1. this作为全局变量2. 作为对象方法的调用3. 作为构造函数调用4. apply调用 this是Javascript语言的一个关键字.它代表函数运行时,自动生成的一个内部对象,只能在函数 ...
- layer.open
1.type-基本层类型 类型:Number,默认:0 layer提供了5种层类型.可传入的值有:0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层). 若你采用layer. ...
- 【读书笔记】iOS-button只显示在一个界面的右下角,不管界面大小怎么变化(xib,没有使用自动布局)(一)
一,新建立一个工程,Hello,如图所示. 二,Xcode--->New--->File--->FirstViewController---->选中Also create XI ...
- Apex 的 Trigger 类简介
Apex Triggers Apex 触发器(Apex Triggers)是一种特殊的 Apex 类.它的主要作用是在一条记录被插入.修改.删除之前或之后自动执行一系列的操作.每一个 Trigger ...
- 新浪微博POI点签到数据及可视化的初步成果
目前仅对山东省区域进行了抓取,权限不够高,抓取的速度非常慢,所以导致效率比较低... 数据抓取采用调用微博开放平台API的方法,数据存储采用mysql,格点数据分辨率为30″,山东省的MBR范围内(包 ...
- Linux 下修改网卡MAC地址
Linux下修改网卡MAC地址 by:授客 QQ:1033553122 例子:修改网卡接口eth0的mac地址 #停用网卡接口,比如eth0 # ifconfig eth0 down #编辑对应的网卡 ...
- 腾讯云部署golang flow流程,vue.js+nginx+mysql+node.js
这次总算把js-ojus/flow的ui部署到腾讯云上,比较吐槽的就是,为啥这么复杂,vue.js前后端分离,比golang编写的部署方面复杂几万倍.真是浪费人生啊. golang+sqlite写的东 ...