gengxin
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
// Keep the native Page lifecycle, but hydrate the correct account before any
|
||||
// story page reads/writes storage. This also covers cold starts from shares.
|
||||
const bridge = require('./platformBridge')
|
||||
const LIFECYCLE_METHODS = new Set(['onLoad', 'onShow', 'onReady', 'onHide', 'onUnload'])
|
||||
const CLEANUP_METHOD = /^(?:destroy|clear|unbind|pause|invalidate|beginPauseLock)/
|
||||
module.exports = function registerTangPage(options) {
|
||||
function isCurrent(page) {
|
||||
return !page.__tangDead && !page.__tangOriginalUnloaded
|
||||
&& page.__tangVisible && page.__tangScope === bridge.getScope()
|
||||
}
|
||||
function returnHome(page) {
|
||||
if (page.__tangRedirected || page.__tangDead) return
|
||||
page.__tangRedirected = true
|
||||
wx.reLaunch({ url: '/tang-detective/pages/home/home' })
|
||||
}
|
||||
function cleanUp(page, name) {
|
||||
if (!page.__tangLoaded || typeof options[name] !== 'function') return
|
||||
if (name !== 'onUnload' && page.__tangOriginalUnloaded) return
|
||||
if (name === 'onUnload') {
|
||||
if (page.__tangOriginalUnloaded) return
|
||||
page.__tangOriginalUnloaded = true
|
||||
}
|
||||
page.__tangCleaning = true
|
||||
try {
|
||||
options[name].call(page)
|
||||
} finally {
|
||||
// This exception is synchronous only; pending timers and audio callbacks
|
||||
// regain the normal visible/account/dead guards as soon as cleanup ends.
|
||||
page.__tangCleaning = false
|
||||
}
|
||||
}
|
||||
function deliverReady(page) {
|
||||
if (!isCurrent(page) || !page.__tangLoaded || !page.__tangHasShown
|
||||
|| !page.__tangReadyRequested || page.__tangReadyDelivered) return
|
||||
page.__tangReadyDelivered = true
|
||||
if (typeof options.onReady === 'function') options.onReady.call(page)
|
||||
}
|
||||
const guarded = { ...options }
|
||||
Object.keys(options).forEach(key => {
|
||||
// Event handlers such as onAudioTimeUpdate are ordinary guarded methods,
|
||||
// even though their names begin with "on".
|
||||
if (typeof options[key] !== 'function' || LIFECYCLE_METHODS.has(key)) return
|
||||
guarded[key] = function (...args) {
|
||||
if (this.__tangCleaning) {
|
||||
// Release resources across an account change, but do not run helpers
|
||||
// such as saveCurrentAudioTime against the newly selected account.
|
||||
if (this.__tangScope === bridge.getScope() || CLEANUP_METHOD.test(key)) {
|
||||
return options[key].apply(this, args)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (this.__tangDead || this.__tangOriginalUnloaded || !this.__tangLoaded || !this.__tangVisible) return
|
||||
if (this.__tangScope && this.__tangScope !== bridge.getScope()) {
|
||||
returnHome(this)
|
||||
return
|
||||
}
|
||||
return options[key].apply(this, args)
|
||||
}
|
||||
})
|
||||
Page({
|
||||
...guarded,
|
||||
data: { ...(options.data || {}), tangBootPending: true },
|
||||
tangIgnoreBootTap() {},
|
||||
onLoad(query) {
|
||||
this.__tangQuery = query
|
||||
this.__tangScope = bridge.getScope()
|
||||
this.__tangDead = false
|
||||
this.__tangVisible = false
|
||||
this.__tangLoaded = false
|
||||
this.__tangCleaning = false
|
||||
this.__tangOriginalUnloaded = false
|
||||
this.__tangRedirected = false
|
||||
this.__tangShowGeneration = 0
|
||||
this.__tangReadyRequested = false
|
||||
this.__tangReadyDelivered = false
|
||||
this.__tangHasShown = false
|
||||
const nativeSetData = this.setData
|
||||
this.setData = function (...args) {
|
||||
if (this.__tangScope !== bridge.getScope()) return
|
||||
if (!this.__tangCleaning && !isCurrent(this)) return
|
||||
return nativeSetData.apply(this, args)
|
||||
}
|
||||
this.__tangBoot = bridge.open()
|
||||
},
|
||||
onShow() {
|
||||
if (this.__tangDead) return
|
||||
this.__tangVisible = true
|
||||
const generation = ++this.__tangShowGeneration
|
||||
const scope = bridge.getScope()
|
||||
if (this.__tangOriginalUnloaded || scope !== this.__tangScope) {
|
||||
returnHome(this)
|
||||
return
|
||||
}
|
||||
Promise.resolve(this.__tangBoot).then(() => {
|
||||
if (this.__tangDead || !this.__tangVisible || generation !== this.__tangShowGeneration) return
|
||||
if (bridge.getScope() !== scope) {
|
||||
returnHome(this)
|
||||
return
|
||||
}
|
||||
if (!this.__tangLoaded) {
|
||||
this.__tangLoaded = true
|
||||
if (options.onLoad) options.onLoad.call(this, this.__tangQuery)
|
||||
if (!isCurrent(this)) return
|
||||
this.setData({ tangBootPending: false })
|
||||
}
|
||||
if (options.onShow) options.onShow.call(this)
|
||||
this.__tangHasShown = true
|
||||
deliverReady(this)
|
||||
}).catch(() => {
|
||||
if (isCurrent(this) && generation === this.__tangShowGeneration) {
|
||||
wx.showToast({ title: '故事暂时未能打开,请返回重试', icon: 'none' })
|
||||
}
|
||||
})
|
||||
},
|
||||
onReady() {
|
||||
this.__tangReadyRequested = true
|
||||
deliverReady(this)
|
||||
},
|
||||
onHide() {
|
||||
this.__tangVisible = false
|
||||
++this.__tangShowGeneration
|
||||
try {
|
||||
cleanUp(this, 'onHide')
|
||||
} finally {
|
||||
// A hidden page from an obsolete account must not retain contexts with
|
||||
// callbacks that directly reference storage instead of guarded methods.
|
||||
try {
|
||||
if (this.__tangScope !== bridge.getScope()) cleanUp(this, 'onUnload')
|
||||
} finally {
|
||||
bridge.flush()
|
||||
}
|
||||
}
|
||||
},
|
||||
onUnload() {
|
||||
this.__tangDead = true
|
||||
this.__tangVisible = false
|
||||
++this.__tangShowGeneration
|
||||
try {
|
||||
cleanUp(this, 'onUnload')
|
||||
} finally {
|
||||
bridge.flush()
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user