In applets, App(…) And the Page (…). Are two of the most familiar and commonly used functions, and today we will take a look at their internal implementation, as well as the initialization process when called.
Some time ago, our public number reprinted the praise technical team “from the source to see the micro channel small program start process”, this article recorded the basic code structure of the small program framework, the start process, and the process of program instantiation, very worth reading again and again. You can also read this article as a review or summary of the article.
An overview of
In wechat developer tools, compile and run your applet project, then open the console, type document and press Enter, you can see the complete page-frame.html loaded by the WebView when the applet is running, as shown below:
By analyzing this HTML file, we can get the small program start execution process is roughly as follows:
This figure is from the article above, and we won’t repeat the process here, but let’s look at the App() and Page() in detail. These two functions are defined in the applets framework waservice.js and instantiated with calls in app.js and page.js for each page.
By executing the openVendor() method in the console of wechat developer tools, you can open the directory where the small program framework is located as follows:
/Users/ user name /Library/Application Support/ wechat Web developer tools/Basic Library version Directory
Copy the code
This paper takes 1.9.94 basic library as an example for analysis. The structure of the waservice.js file is as follows:
; (function(global) {
// Define and load WeixinJSBridge
// Define and load NativeBuffer
// Define and load wxConsole
// Define and load WeixinWorker
// Reporter definition and loading
// __appServiceSDK__ is defined and loaded
wx = __appServiceSDK__.wx,
// ExParser is defined and loaded
// Define and load __virtualDOM__
// Define and load __appServiceEngine__
Page = __appServiceEngine__.Page,
Component = __appServiceEngine__.Component,
Behavior = __appServiceEngine__.Behavior,
__webview_engine_version__ = .02,
App = __appServiceEngine__.App,
getApp = __appServiceEngine__.getApp,
getCurrentPages = __appServiceEngine__.getCurrentPages,
__createPluginGlobal = __appServiceEngine__.__createPluginGlobal,
// Define and load __wxModule__
definePlugin = __wxModule__.definePlugin,
requirePlugin = __wxModule__.requirePlugin;
// define method definition
// define the require method
global.App = App;
global.Page = Page;
global.Component = Component;
global.Behavior = Behavior;
Global. __webview_engine_version__ = 0.02;
global.getApp = getApp;
global.getCurrentPages = getCurrentPages;
global.wx = wx;
global.definePlugin = __wxModule__.definePlugin;
global.requirePlugin = __wxModule__.requirePlugin;
})(this);
Copy the code
We found that WAService. Js defines WeixinJSBridge and WX as two basic API sets, and also contains some other framework cores, such as ExParser, __virtualDOM__, __appServiceEngine__, etc. __appServiceEngine__ provides the framework’s most basic external interface, such as App, Page, Component, Behavior, etc. Exparser provides the low-level capabilities of the framework, such as instantiation of components, data change listening, View layer and logic layer interaction, etc. __virtualDOM__ is used to connect __appServiceEngine__ and ExParser, for example, to format an object passed in by the developer’s Page method and pass in the corresponding exParser method. (This analysis is taken from the article above.)
The global functions App() and Page() are references to the __appServiceEngine__ object of the same name defined in WAService. Let’s take a brief look at their internal implementation and initialization processes.
App() and getApp() functions
According to the wechat applets development document, the App() function is used to register a applets, receive an object object parameter, which specifies the applets life cycle function, etc. As we can see from the function prompt of wechat developer tools, the declaration of App() function is as follows:
function App(options: _AppOptions): void
Copy the code
The properties of the object (_AppOptions) are described as follows:
In addition, the global getApp() function can be used to get an instance of an applet, which is declared as follows:
function getApp(): object
Copy the code
Internal implementation
In the __appServiceEngine__ object, the App and getApp properties are defined as follows:
// where t is the __appServiceEngine__ object
var i = n(17);
Object.defineProperty(t, "App", {
enumerable: ! 0,
get: function() {
return i.appHolder
}
}),
Object.defineProperty(t, "getApp", {
enumerable: ! 0,
get: function() {
return i.getApp
}
}),
Copy the code
The corresponding implementations of these two properties are appHolder() and getApp() methods, defined as follows:
l = void 0,
t.appHolder = (0, i.surroundByTryCatch)(function(e) {
l = new y(e)
}, "create app instance"),
t.getApp = function() {
return l
},
Copy the code
In appHolder(), pass an object passed in from the outside to y(… The getApp() method initializes an applet instance object and assigns the result to the variable L, while the getApp() method simply returns L, returning the current applet object.
App instance initialization process
In page-frame.html, we know that the applet framework immediately requires (‘app.js’) to register the applet instance after app.js is loaded. The App() function is called (the developers have defined the input object in app.js) as follows:
<script src="./app.js"></script>
<script>require("app.js")</script>
Copy the code
In the App() function, y(…) is eventually called. Method, where y(…) The definition of WAService is quite long, so we will not post the code here. For details, please refer to WAService. Js by yourself.
-
Declare that the app.getCurrentPage method is deprecated, use the getCurrentPages() global method;
-
Bind life cycle functions, that is, bind properties defined by external input objects to applets instance objects, including onLaunch, onShow, onHide, onUnlaunch, and onPageNotFound;
-
Bind other properties (including data and methods) that the developer has defined, and verify that the property name is “getCurrentPage” and warn if it is;
-
Determine whether to register error reporting according to whether the onError attribute is defined externally.
-
Check the launch parameters (from __wxconfig. appLaunchInfo) and call the onLaunch and onShow methods in turn;
-
Switch back to onShow and onHide before registration;
-
Register the callback onPageNotFound for pages not found;
-
Return the instance to the App() function for caching.
The Page() and getCurrentPages() functions
According to the documentation, the Page() function is used to register a Page and receives an Object object parameter that specifies the Page’s initial data, lifecycle functions, event handlers, and so on. Page() is declared as follows:
function Page(page: PageOptions): void
Copy the code
The properties of the object object (PageOptions) are described as follows:
In addition, the getCurrentPages() function is used to get an instance of the current page stack, presented as an array in stack order, with the first element being the home page and the last element being the current page. Its statement is as follows:
function getCurrentPages(): object[]
Copy the code
Internal implementation
Similarly, in the __appServiceEngine__ object, the Page and getCurrentPages properties are defined as follows:
var r = n(2);
Object.defineProperty(t, "Page", {
enumerable: ! 0,
get: function() {
return r.pageHolder
}
}),
Object.defineProperty(t, "getCurrentPages", {
enumerable: ! 0,
get: function() {
return r.getCurrentPages
}
}),
Copy the code
The corresponding implementations of these two attributes are pageHolder() and getCurrentPages() methods, defined as follows:
Var k = void 0, // save the page currently displayed (top of stack)
X = [], // Save the loaded page history stack array
// where t is the __appServiceEngine__ object
t.getCurrentPage = function() {
return k
},
t.getCurrentPages = function() {
var e = [];
return x.forEach(function(t) {
e.push(t.page)
}),
e
},
M = {}, // cache all registered pages
t.pageHolder = function(e) {
if (! __wxRouteBegin) throw (0, f.ror)("Page register error ", "Please do not register multiple Pages in "+ __wxRoute + ".js"),
new a.AppServiceEngineKnownError("Please do not register multiple Pages in " + __wxRoute + ".js");
__wxRouteBegin = ! 1;
var t = __wxRoute;
if (! A(t)) throw (0, f.ror)("Page registration error ", __wxRoute + "has not been declared in app.json."),
new a.AppServiceEngineKnownError(__wxRoute + " has not been declared in app.json.");
var n = "undefined" ! = typeof __wxAppCode__ ? __wxAppCode__[t + ".json"] || {}: {};
if ("Object" ! == (0, f.getDatatype)(e)) throw (0, f.ror)("Page register error ", "Options is not object: " + JSON.stringify(e) + " in " + __wxRoute + ".js"),
new a.AppServiceEngineKnownError("Options is not object: " + JSON.stringify(e) + " in " + __wxRoute + ".js"); (0, f.info)("Register Page: " + t),
void 0 ! == n.usingComponents ? (__virtualDOM__.Page(e), M[t] = exparser.Component._list[t]) : M[t] = e
},
Copy the code
By analyzing the above code, we can summarize the processing flow of pageHolder method as follows:
-
__wxRouteBegin = true is set before loading a page.
-
Determine whether __wxRouteBegin is false, if so, throw a multiple call to Page registration error;
-
Set __wxRouteBegin to false to avoid repeated execution by subsequent code.
-
Call A (…). Method checks if the current page is defined in app.json and throws an error if not;
-
Check if the external input parameter (PageOptions) is an Object, if not, throw an error;
-
Determine whether the current Page uses a custom component (Page objects that use custom components are configured differently), and then cache the current Page configuration into the M object.
In addition, we can see that, unlike App(), external (lifecycle) code passed in through the Page() function is not executed here, but instead waits for the Page to be Ready and instantiated when it enters the Page.
Page initialization process
Similarly, according to the page-frame.html loading order, after app.js has been loaded and executed, the applet will then load all the custom component code (if any) in that order and automatically register. The custom Component plays an important role in the development of small programs. It can enrich the basic functions of small programs and has more powerful capabilities than Page. Therefore, the implementation is more complex and the space is limited.
After loading the code that executes the custom component, the applet immediately loads the code for each page in sequence and executes require(…). Register the page as follows:
<script>__wxRoute = "pages/index/index"; __wxRouteBegin = true</script>
<script>__wxAppCurrentFile__ = "pages/index/index.js"</script>
<script src="./pages/index/index.js"></script>
<script>require("pages/index/index.js")</script>
<script>
if(__wxRouteBegin) {
Console. group("Tue Jun 26 2018 17:53:09 GMT+0800 (CST) page compiler error ")
Console. error(" Pages /index/index.js has a script error or does not call Page() correctly ")
console.groupEnd()
}
</script>
<! -- Load registration next Page -->
Copy the code
-
Set __wxRoute to the current Page path and __wxRouteBegin to true.
-
Set __wxAppCurrentFile__ to the current loaded file path.
-
Load the page code and execute the registration page (refer to the pageHolder process above);
-
The page is successfully registered by checking whether __wxRouteBegin is false (because in pageHolder, __wxRouteBegin is set to false).
-
Load other pages in turn;
-
Waiting for the Page Ready and Page instantiation, Page Load is triggered by the wx.onAppRoute event.
In page-frame. HTML, the DOCUMENT_READY event is emitted in the body after all the JS code in the head has been executed, as follows:
<body>
<script>
if (document.readyState == 'complete') {
window.__global.alert('DOCUMENT_READY')
} else {
var fn = function(event) {
window.__global.alert('DOCUMENT_READY')
window.removeEventListener("load", fn)
}
window.addEventListener('load', fn)
}
</script>
</body>
Copy the code
In the small program framework WAService. Js, the final DOCUMENT_READY will be converted into wx.onAppRoute event (logic to be verified), and finally the page will be instantiated or switched in wx.onAppRoute event.
PS: The full initialization load process for a small program page will be covered in the next article.
conclusion
This article briefly analyzes the internal implementation of several functions such as App(), getApp() and Page(), getCurrentPages(), hoping to make you better understand the small program instance object and Page loading process, and bring help to your actual development. Finally, the content of this article is just the tip of the iceberg of the bottom framework of the small program, I recommend you to read this article “from the source to see the micro channel small program startup process” and the author organized the mind map, I believe you will have new harvest.