SAPUI5 walkthrough step 6 – modules, dive in – how does modules work?
Welcome to my SAPUI5 Walkthrough, And Dive In blog series, where I’ll not only walkthrough the tutorial, but dive in, to explore the magic behind SAPUI5. Buckle up and sit tight, it’s gonna be a bumpy ride as I’m no expert in any way shape or form, just a humble learner who loves coding and likes to get to the bottom of things =。=
“You just do the programming and solve the problem.
And then onto the next problem and solve that problem.
And solve the next problem too.
And if you solve enough problems, you get to go home.”
— The Martian
I just came back watching the martian, this is one of my favourite lines in that movie, I did change the word ‘math’ to ‘programming’ here, I’d like to see a movie in which Matt Damon solves programming problems 😀
I got asked by one of my friends the other day, hey, Ji, why are you’re writing these posts, isn’t that something most of the developers already knew? And even they don’t, people can find out about it in the Chrome console during a tea break. Well, that’s true, for one, I don’t know it, I mean I don’t before dive into the source code, and writing about it helps me sort out my thoughts, this is my way of rubber duck debugging. And reading the framework source code is like reading a suspense novel, you’re the one to reveal the mysteries, isn’t that like the best?
Alright, clearly I’m having too much tea, let’s take a deep breath and dive in.
First let’s take a quick look at How does a module defined?, I removed all the methods except the show method of our MessageToast module, so that it can be fit into my screenshot below. We define a module, by calling sap.ui.define, the first parameter could be (1) the name of the module, when omitted, the loader determines the name from the request, that’s what we’re doing here. The rest of the parameters are (2) the array of dependencies and (3) the module factory function, and (4) the boolean depending on whether an export to global names is required.
Alright, with what’s our MessageToast module looks like in mind, let’s starting debugging, to reveal these mysteries:
– How does a module required?
– How does a module loaded?
– How many states a module could have?
– How does a module made available to global name space?
In our example code, the MessageToast module is consumed as one of the dependencies of the App.controller.js.
The MessageToast module is required in the requiredAll method which is responsible for resolving the dependencies.
Within requireAll, the requireModule method is called.
requireModule looks for MessageToast in the global mModules map, if it does not exist, the oModule object will be created, with its first property, state, with value INITIAL.
Before we go any further, let’s take a look at how many states a module could have, this would give us a good picture of what’s next to come.
INITIAL = 0, // Module neither has been required nor preloaded not declared, but someone asked for it. PRELOADED = -1, // Module has been preloaded, but not required or declared LOADING = 1, // Module has been declared. LOADED = 2, // Module has been loaded, but not yet executed. EXECUTING = 3, // Module is currently being executed READY = 4, // Module has been loaded and executed without errors. FAILED = 5, // Module either could not be loaded or execution threw an error
Next, we set module state to LOADING, then, a sync ajax request action is performed, MessageToast.js is retrieved and its content is set to the data property of the oModule object, and also, the module state is now set to LOADED.
One of the advantages of AMD format is that modules can be loaded asynchronously, but as you can see, modules in SAPUI5 is now loaded synchronously, according to the documentation: sap.ui.define currently loads modules with synchronous XHR calls. This is basically a tribute to the synchronous history of UI5.
With module loaded, the execModule method is called to execute module.
We first set module state to EXECUTING, then calls window.eval on the module data.
By executing our MessageToast module, we’ll go through the sap.ui.define -> requireAll -> requireEachModule -> execEachModule process again as MessageToast depends on another three modules as we saw earlier. Once dependencies resolved, the callback which we saw at screenshot #5 is called with the aModules array, that’s where the dependencies are kept.
In the callback function, the MessageToast factory function is called with the depended modules.
That results the MessageToast object filled with all its methods returned and assigned to the content property of oModule object.
Next, we’ll be exporting our module to the global name space cause we passed in export true when we (right, not us, but the framework) define the module.
jQuery.sap.setObject method is called to do the exporting.
Which essentially adds the MessageToast object to the sap.m global namespace / object.
Lastly, we set module state to READY, and clear out the data property.
Then, we come back, the MessageToast and all its methods, .show included are made available to us.
Our Hello World is framed with the beautiful MessageToast control.
The end, happy coding 🙂