* Multi-store supported
* Optimizing view update performance of store proxy update
This commit is contained in:
dntzhang 2019-10-07 12:23:20 +08:00
parent a4f6b89533
commit 1417060690
5 changed files with 106 additions and 97 deletions

View File

@ -87,71 +87,27 @@ export function define(name, ctor) {
}
}
export function getPath(obj) {
if (getType(obj) === 'Array') {
const result = {}
obj.forEach(item => {
if (typeof item === 'string') {
result[item] = true
} else {
const tempPath = item[Object.keys(item)[0]]
if (typeof tempPath === 'string') {
result[tempPath] = true
} else {
if (typeof tempPath[0] === 'string') {
result[tempPath[0]] = true
} else {
tempPath[0].forEach(path => (result[path] = true))
}
}
}
})
return result
} else {
return getUpdatePath(obj)
}
export function getPath(obj, out, name) {
const result = {}
obj.forEach(item => {
if (typeof item === 'string') {
result[item] = true
} else {
const tempPath = item[Object.keys(item)[0]]
if (typeof tempPath === 'string') {
result[tempPath] = true
} else {
if (typeof tempPath[0] === 'string') {
result[tempPath[0]] = true
} else {
tempPath[0].forEach(path => (result[path] = true))
}
}
}
})
if(out) out[name] = result
return result
}
export function getUpdatePath(data) {
const result = {}
dataToPath(data, result)
return result
}
function dataToPath(data, result) {
Object.keys(data).forEach(key => {
result[key] = true
const type = getType(data[key])
if (type === 'Object') {
_objToPath(data[key], key, result)
} else if (type === 'Array') {
_arrayToPath(data[key], key, result)
}
})
}
function _objToPath(data, path, result) {
Object.keys(data).forEach(key => {
result[path + '.' + key] = true
delete result[path]
const type = getType(data[key])
if (type === 'Object') {
_objToPath(data[key], path + '.' + key, result)
} else if (type === 'Array') {
_arrayToPath(data[key], path + '.' + key, result)
}
})
}
function _arrayToPath(data, path, result) {
data.forEach((item, index) => {
result[path + '[' + index + ']'] = true
delete result[path]
const type = getType(item)
if (type === 'Object') {
_objToPath(item, path + '[' + index + ']', result)
} else if (type === 'Array') {
_arrayToPath(item, path + '[' + index + ']', result)
}
})
}

View File

@ -24,5 +24,6 @@ function getGlobal() {
export default {
store: null,
root: getGlobal(),
mapping: {}
mapping: {},
isMultiStore: false
}

View File

@ -1,35 +1,49 @@
import { diff } from './vdom/diff'
import JSONProxy from './proxy'
import { getUse } from './util'
import options from './options'
export function render(vnode, parent, store) {
parent = typeof parent === 'string' ? document.querySelector(parent) : parent
if (store) {
store.instances = []
extendStoreUpate(store)
store.data = new JSONProxy(store.data).observe(false, function (patch) {
const patchs = {}
if (patch.op === 'remove') {
// fix arr splice
const kv = getArrayPatch(patch.path, store)
patchs[kv.k] = kv.v
update(patchs, store)
} else {
const key = fixPath(patch.path)
patchs[key] = patch.value
update(patchs, store)
if (store.data) {
observeStore(store)
} else {
//Multi-store injection
for (let key in store) {
observeStore(store[key])
}
})
options.isMultiStore = true
}
parent.store = store
}
return diff(null, vnode, parent, false)
}
function observeStore(store) {
store.instances = []
store.updateSelfInstances = []
extendStoreUpate(store)
store.data = new JSONProxy(store.data).observe(false, function (patch) {
const patchs = {}
if (patch.op === 'remove') {
// fix arr splice
const kv = getArrayPatch(patch.path, store)
patchs[kv.k] = kv.v
update(patchs, store)
} else {
const key = fixPath(patch.path)
patchs[key] = patch.value
update(patchs, store)
}
})
}
function update(patch, store) {
store.update(patch)
}
@ -57,6 +71,9 @@ function extendStoreUpate(store) {
instance.update()
}
})
this.updateSelfInstances.forEach(instance => {
if (instance._updateSelfPath && needUpdate(patch, instance._updateSelfPath)) {
instance.usingSelf = getUse(store.data, typeof instance.useSelf === 'function' ? instance.useSelf() : instance.useSelf)
instance.updateSelf()

View File

@ -79,7 +79,7 @@ export function isArray(obj) {
}
export function getUse(data, paths) {
export function getUse(data, paths, out, name) {
const obj = []
paths.forEach((path, index) => {
const isPath = typeof path === 'string'
@ -105,7 +105,8 @@ export function getUse(data, paths) {
}
obj[key] = obj[index]
}
})
})
if(out) out[name] = obj
return obj
}

View File

@ -22,27 +22,61 @@ export default class WeElement extends HTMLElement {
this.store = p.store
p = p.parentNode || p.host
}
if (this.store) {
this.store.instances.push(this)
}
if (this.use) {
let use
let use
if(typeof this.use === 'function'){
use = this.use()
}else{
use = this.use
}
this._updatePath = getPath(use)
this.using = getUse(this.store.data, use)
if(options.isMultiStore){
let _updatePath = {}
let using = {}
for(let storeName in use){
_updatePath[storeName] = {}
using[storeName] = {}
getPath(use[storeName], _updatePath, storeName)
getUse(this.store[storeName].data, use[storeName], using, storeName)
this.store[storeName].instances.push(this)
}
this.using = using
this._updatePath = _updatePath
}else{
this._updatePath = getPath(use)
this.using = getUse(this.store.data, use)
this.store.instances.push(this)
}
} else {
this.constructor.use && (this.using = getUse(this.store.data, this.constructor.use))
if(this.constructor.use ){
if(options.isMultiStore){
this._updatePath = getPath(use[storeName], storeName)
this.using = getUse(this.store[storeName].data, use[storeName], storeName)
this.store[storeName].instances.push(this)
}else{
this.using = getUse(this.store.data, this.constructor.use)
this.store.instances.push(this)
}
}
}
if(this.useSelf){
const use = typeof this.useSelf === 'function' ? this.useSelf() : this.useSelf
this._updateSelfPath = getPath(use)
this.usingSelf = getUse(this.store.data, use)
if(options.isMultiStore){
for(let storeName in use){
this._updateSelfPath = getPath(use[storeName], storeName)
this.usingSelf = getUse(this.store[storeName].data, use[storeName], storeName)
this.store[storeName].updateSelfInstances.push(this)
}
}else{
this._updateSelfPath = getPath(use)
this.usingSelf = getUse(this.store.data, use)
this.store.updateSelfInstances.push(this)
}
}
this.attrsToProps()
this.beforeInstall()
@ -69,7 +103,7 @@ export default class WeElement extends HTMLElement {
}
this.beforeRender()
options.afterInstall && options.afterInstall(this)
const rendered = this.render(this.props, this.store)
this.__hasChildren = Object.prototype.toString.call(rendered) === '[object Array]' && rendered.length > 0