feat:
* Multi-store supported * Optimizing view update performance of store proxy update
This commit is contained in:
parent
a4f6b89533
commit
1417060690
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -24,5 +24,6 @@ function getGlobal() {
|
|||
export default {
|
||||
store: null,
|
||||
root: getGlobal(),
|
||||
mapping: {}
|
||||
mapping: {},
|
||||
isMultiStore: false
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue