ServiceNow JavaScript performance check based on different strategies using ES5, ES12, GlideRecord and GlideQuery
My role as a developer in the projects has been reduced significantly by today, but I was looking forward to the day, when a newer JavaScript version than ES5 (ECMAScript 5) will be available in ServiceNow. So finally in the Tokyo Release it happened. In case of scoped applications, the ES12 (ECMAScript 2021) version of Javascript is available as well. Finally, I had the chance to execute some test cases, which had been on my mind for long time to check the performance of the system, using different combination of GlideRecord, GlideQuery ES5 and ES12.
Test Case
In case of reference qualifier definitions I'm always thinking about how the filter condition can be implemented as simple as possible. One of the advantages of ES12 syntax is, that it is possible to write compact codes. I was curious of the performance impact of data filtering with the new version of JS.
I have selected a somewhat complex case for testing. There is a User reference field which is called Special Contact. The users, which can be selected are based on the following filter criteria:
Need to collect all users who are subscribed for the selected CI and the title of the user matches the following pattern:
Junior or Senior or Expert developer in level 1 or 2 (For example: Junior developer 2)?
I prepared this setup by selecting some users randomly from the sys_user table and modifying their Title property. It can be seen on the image below that there are two users where the condition is met:
I have connected these users to a CI with a "subscribed by type" relationship:
I have also added the new field to a form of Task extended table and defined the reference qualifier as a function call from a script include.
The Code
I tried to keep the code as simple as possible and used only generic objects. Let’s see how the three scripts look like:
The first function contains the “classic way” of how data can be gathered:
getSubscibedUsersV1: function(ciSysId) {
var usrList = [];
var suGr = new GlideRecordSecure("cmdb_subscriber");
suGr.addQuery("item", "=", ciSysId);
suGr.query();
while (suGr.next()) {
if (suGr.user.title && suGr.user.title.match(/^(Junior|Senior) Developer [1,2]$/g)) {
usrList.push(suGr.getValue("user"));
}
}
return usrList.join(",");
}
In the second use case, I used the GlideQuery and some Javascript capabilities like map and filter, in order to gather the corresponding data only:
领英推荐
getSubscibedUsersV2: function(ciSysId) {
return new global.GlideQuery('cmdb_subscriber')
.withAcls()
.where("item", "=", ciSysId)
.select("user.title", "user.sys_id")
.filter(function(item) {
return item.user.title && item.user.title.match(/^(Junior|Senior) Developer [1,2]$/g);
})
.toArray(100)
.map(function(k){ return k.user.sys_id; })
.join(",");
}
The difference between the 2nd and 3rd case is minuscule. I started using some new JS syntax, for example Lambda expressions:
getSubscibedUsersV3: function(ciSysId) {
return new global.GlideQuery('cmdb_subscriber')
.withAcls()
.where("item", "=", ciSysId)
.select("user.title", "user.sys_id")
.filter(item => item.user.title && item.user.title.match(/^(Junior|Senior) Developer [1,2]$/g))
.toArray(100)
.map(item => item.user.sys_id)
.join(',');
}
In the second and third use case I assumed that the number of records cannot be greater than 100, otherwise the toArray function cannot be used.
Important! If you select the ES5 as Javascript mode in the application, the ES6+ syntax cannot be used.
Recommendation: Use the GlideRecordSecure or GlideQuery(...).withAcls() whenever is possible instead of bypassing the security rules.
Executing the test cases
Everything was ready to start testing. The test case was very simple I just selected a CI and opened the User selector window:
I have used a demo ServiceNow instance and the measurement was defined in the functions based on a simple execution time calculation. I selected 3 CIs and setup different amount of relations:
I used the following combinations of script execution for testing the performance:
I have done several tests and repeated the actions multiple times, and used average values based on the results. The measured results can be observed on the image below:
Conclusion
Honestly, I’m a bit surprised. I knew that the performance of GlideQuery is a bit worse than the GlideRecord, but I thought ES12 increases the effectiveness of JS executions, but in this case it didn't. The picture shows that the run times are very close to each other, which means that there is no significant difference between the cases.
There are a lot of great things / possibilities available in the new version of Javascript, but I think, the added value of this case is that using GlideQuery and some ES12 features provides the possibility to write easier / shorter / more compact code, which can help reduce the lead time of implementation, but it won't be faster.
It is up to you to decide if you want to keep on using the classic way of coding, or start something new (is it really new? ??), like Lambda expressions.
ServiceNow Certified Master Architect
2 年Attila Varga, great article for #ServiceNow developers that wants quality! Thank you for sharing and your effort to test and document it!
ServiceNow Certified Master Architect
2 年Nice to see some data on this. I think the reason you see little difference in performance is that the JS engine is still Rhino (ES5) and any ES6+ code is transpiled to ES5. As you said, usage is purely a developer preference at the moment.
Simplify Agile for Complex Organizations | Lean-Agile & Project management expert | Lecturer | Helping career changers
2 年Wow, great post Attila ;)
Senior Business Analyst | Project Manager | Consultant | ServiceNow | 5xCIS certified I ITSM | HRSD | PPM | CSM | FSM | Digital Solutions | ITIL 4 | Agile | PRINCE2
2 年Great read, thanks Attila Varga!