js服務
weex中注冊js服務,會在目前運作的js環境中注入一個對應service的create方法傳回的對象,這個對象有兩種傳回形式:
- 在傳回對象的instance上聲明一個執行個體服務;
- 直接在傳回對象對象上聲明一個服務。
如下面代碼中的InstanceService和NormalService
service.register(SERVICE_NAME /* same string with native */, {
/**
* JSService lifecycle. JSService `create` will before then each instance lifecycle `create`. The return param `instance` is Weex protected param. This object will return to instance global. Other params will in the `services` at instance.
*
* @param {String} id instance id
* @param {Object} env device environment
* @return {Object}
*/
create: function(id, env, config) {
return {
instance: {
InstanceService: function(weex) {
var modal = weex.requireModule('modal')
return {
toast: function(title) {
modal.toast({ message: title })
}
}
}
},
NormalService: function(weex) {
var modal = weex.requireModule('modal')
return {
toast: function(title) {
modal.toast({ message: title })
}
}
}
}
},
/**
* JSService lifecycle. JSService `refresh` will before then each instance lifecycle `refresh`. If you want to reset variable or something on instance refresh.
*
* @param {String} id instance id
* @param {Object} env device environment
*/
refresh: function(id, env, config){
},
/**
* JSService lifecycle. JSService `destroy` will before then each instance lifecycle `destroy`. You can deleted variable here. If you doesn't detete variable define in JSService. The variable will always in the js runtime. It's would be memory leak risk.
*
* @param {String} id instance id
* @param {Object} env device environment
* @return {Object}
*/
destroy: function(id, env) {
}
})
源碼了解
我們從源碼的角度了解service的注冊過程,我們可以在runtime的代碼中找到建立服務的方法:
function createServices (id, env, config) {
// Init JavaScript services for this instance.
const serviceMap = Object.create(null)
serviceMap.service = Object.create(null)
services.forEach(({ name, options }) => {
if (process.env.NODE_ENV === 'development') {
console.debug(`[JS Runtime] create service ${name}.`)
}
const create = options.create
if (create) {
try {
const result = create(id, env, config)
Object.assign(serviceMap.service, result)
Object.assign(serviceMap, result.instance)
}
catch (e) {
console.error(`[JS Runtime] Failed to create service ${name}.`)
}
}
})
delete serviceMap.service.instance
Object.freeze(serviceMap.service)
return serviceMap
}
我們看到在第3行和第4行分别建立了一個serviceMap對象和一個serviceMap上的service對象,這是用來将來儲存我們通過兩種方式建立的服務的;
接下來我們看第10行,如果注冊的服務有create方法,那麼我們取它的傳回值為result,接下來分别把result上的屬性複制到serviceMap.service,把result.instance上的屬性複制到serviceMap上,最後傳回這個serviceMap。
那麼這個serviceMap是怎麼放到全局的呢,我們繼續查找源碼,可以跟蹤到createInstanceContext方法,
function createInstanceContext (id, options = {}, data) {
const weex = new WeexInstance(id, options, data)
const bundleType = options.bundleType || 'Vue'
instanceTypeMap[id] = bundleType
const framework = runtimeConfig.frameworks[bundleType]
if (!framework) {
return new Error(`[JS Framework] Invalid bundle type "${bundleType}".`)
}
// prepare js service
const services = createServices(id, {
weex,
config: options,
created: Date.now(),
framework: bundleType,
bundleType
}, runtimeConfig)
Object.freeze(services)
// prepare runtime context
const runtimeContext = Object.create(null)
Object.assign(runtimeContext, services, {
weex,
getJSFMVersion,
requireModule: (...args) => weex.requireModule(...args),
__WEEX_CALL_JAVASCRIPT__: receiveTasks,
services // Temporary compatible with some legacy APIs in Rax
})
Object.freeze(runtimeContext)
// prepare instance context
const instanceContext = Object.assign({}, runtimeContext)
if (typeof framework.createInstanceContext === 'function') {
Object.assign(instanceContext, framework.createInstanceContext(id, runtimeContext, data))
}
Object.freeze(instanceContext)
return instanceContext
}
這個方法是weex的runtime用來建立一個執行個體的上下文運作環境的,我們看到代碼的第12行,調用了createServices來建立services對象,而這個services就是我們上面說的serviceMap對象了。
接下來我們看到在第21行建立了一個空的對象作為運作時的上下文環境,緊接着在22行,把services等對象上的屬性複制到這個上下文對象上了,而上下文環境上的屬性我們可以當做全局變量來使用。
不好了解的話我們可以結合上面注冊的服務的例子,想象一下createInstanceContext最後傳回這樣一個對象:
{
service:{
NormalService:function(weex){
//...
}
},
InstanceService:function(weex){
//...
}
weex:weex,
getJSFMVersion:getJSFMVersion,
__WEEX_CALL_JAVASCRIPT__
}
這個對象上的屬性會被weex的底層注入到全局上下文運作環境中,即這個對象上的屬性是全局變量。
使用
是以我們就知道service如何在weex中使用了
<script>
var _InstanceService = new InstanceService(weex)
var _NormalService = new service.NormalService(weex)
module.exports = {
created: fucntion() {
// called modal module to toast something
_InstanceService.toast('Instance JSService')
_NormalService.toast('Normal JSService')
}
}
</script>
serviceMap是在instance的create之前服務的create擷取的,是以,要想使用service,需要在執行個體建立之前調用原生平台的代碼執行js服務的注冊代碼完成服務的注冊。
Android和IOS原生平台的注冊代碼這裡不再贅述,參見下面的官方文檔即可。
參考文檔:js服務官方文檔