ECMAScript 7: setTimeout and Arrow Functions

19866
2
05-22-2019 01:00 AM
StephenQuan1
Occasional Contributor III
2 2 19.9K

1. Introduction

This blog talks about implementing your own setTimeout() function in AppStudio.

The blog also highlights ECMAScript 6 and ECMAScript 7 support in Qt 5.12.1 and AppStudio 3.3 features: arrow functions (my favourite), property shorthand, rest parameters and spread syntax.

setTimeout() is a function which executes another function or specified piece of code after waiting for the specified time delay in milliseconds.

The following will execute the following 4 console.log() after waiting 0 - 1000 milliseconds (determined by a random function). Each timer starts simulatenously but their completion times are random making the 4 console.log() appearing in random jumbled order.

    setTimeout( () => console.log("Hello"), randomDelay() )
setTimeout( (a) => console.log(a), randomDelay(), 1 )
setTimeout( (a, b) => console.log(a, b), randomDelay(), 21, 22 )
setTimeout( (a, b, c) => console.log(a, b, c), randomDelay(), 31, 32, 33 )‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

randomDelay() is a function that computes a random time delay from the range of 0 – 1000 milliseconds:

    function randomDelay() {
return Math.floor(1000 * Math.random())
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Here is the console output:

2. AppStudio implementation

setTimeout() is a part of other Javascript development environments, e.g. in Web development and Node.js. It exists globally on the window object.

However, in Qt and AppStudio, there isn’t an equivalent window object or setTimeout() function.

To bring over such a capability you need to implement it yourself.

Here is a sample AppStudio app that includes a simple implementation of setTimeout(). Everytime the button is clicked the 4 setTimeout() functions are triggered with the 4 resulting console.log() appearing in random order.

import QtQuick 2.12
import QtQuick.Controls 2.5
import ArcGIS.AppFramework 1.0

App {
id: app

width: 400 * AppFramework.displayScaleFactor
height: 640 * AppFramework.displayScaleFactor

StackView {
id: stackView

anchors.fill: parent

initialItem: Item {
Button {
text: qsTr("Test")
onClicked: {
setTimeout( () => console.log("Hello"), randomDelay() )
setTimeout( (a) => console.log(a), randomDelay(), 1 )
setTimeout( (a, b) => console.log(a, b), randomDelay(), 21, 22 )
setTimeout( (a, b, c) => console.log(a, b, c), randomDelay(), 31, 32, 33 )
}
}
}
}

function randomDelay() {
return Math.floor(1000 * Math.random())
}

function setTimeout(func, interval, ...params) {
return setTimeoutComponent.createObject(app, { func, interval, params } )
}

function clearTimeout(timerObj) {
timerObj.stop()
timerObj.destroy()
}

Component {
id: setTimeoutComponent
Timer {
property var func
property var params
running: true
repeat: false
onTriggered: {
func(...params)
destroy()
}
}
}
}
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Disclaimer: this is a minimal implementation of setTimeout() not a fully functioning implementation. It is here for the purposes of this blog, specifically to talk about aspects of ECMAScript. If you want to use this implementation you will need to adapt it accordingly.

This implementation of setTimeout() returns a Timer object (instead of a timerId). When the time delay specified in milliseconds has been reached the nominated Javascript function is triggered with the parameters you supplied to setTimeout(). If you wish to abort the action, you can passed the Timer object to the clearTimeout() function.

This implementation will now be deconstructed:

  • Global functions in AppStudio
  • ECMAScript 6 Arrow Functions
  • ECMAScript 6 Property shorthand
  • ECMAScript 6 Rest parameter and Spread syntax

3. Global functions in AppStudio

Functions implemented in the top level component (here, it was App) will be seen by all child components. In this example, we have a StackView which means, all pages that are pushed to the StackView will have access to the setTimeout() function.

4. Arrow functions

The first parameter to setTimeout() refers to a function or code. In our examples, we have been using the ECMAScript 6 arrow function syntax for anonymous functions. e.g. the arrow function (a, b, c) => console.log(a, b, c) appears in the following snippet:

setTimeout( (a, b, c) => console.log(a, b, c), randomDelay(), 31, 32, 33)‍‍‍‍‍‍‍‍‍‍‍

When used appropriately, arrow functions can help improve code readablity and maintainability.

For comparison, let's look at equivalent implementation to the above arrow function.

4.1 Original Anonymous functions

Prior to ECMAScript 6, we could always do anonymous functions, but the syntax was somewhat cumbersome with the required use of the function keyword:

setTimeout( function (a, b, c) { console.log(a, b, c) }, randomDelay(), 31, 32, 33 )‍‍‍‍‍‍‍‍‍‍

4.2 Using a named function

Sometimes, to avoid the use of the anonymous function syntax, I find it better to name things clearly and space out my code for increase readability and maintainability:

function testFunction(a, b, c) {
console.log(a, b, c)
}

setTimeout(testFunction, randomDelay(), 31, 32, 33)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

4.3 Calling console.log directly

For completeness, we recognize that console.log, is, itself, a function reference, so, we can supply this directly to the setTimeout() function.

setTimeout(console.log, randomDelay(), 31, 32, 33)‍‍‍‍‍‍‍‍‍‍

5. Property shorthand syntax

ECMAScript 6 introduces a property shorthand syntax for object creation.

In the following snippets, compare the code for both obj1 and obj2.

They both yield the same value, but the code for obj2 is much shorter and easier to read.

var x = 11
var y = 22
var z = 33
var obj1 = { x: x, y: y, z: z } // obj1 = { x: 11, y: 22, z: 33 }
var obj2 = { x, y, z } // obj2 = { x: 11, y: 22, z: 33 }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

We used the shorthand syntax to simplify the following

setTimeoutComponent.createObject(app, { func:func, internval:interval, args:args } )‍‍‍‍‍‍‍‍‍‍‍

into:

setTimeoutComponent.createObject(app, { func, interval, args } )‍‍‍‍‍‍‍‍‍‍‍

6. Rest parameter and Spread syntax

ECMAScript 6 also introduces rest parameters and spread syntax.

We used it in the declaration of the setTimeout function to pick up all remaining parameters as an array.

function setTimeout(func, interval, ...params) {‍‍‍‍‍‍‍‍‍‍

when called with:

setTimeout( (a, b, c) => console.log(a, b, c), randomDelay(), 31, 32, 33)‍‍‍‍‍‍‍‍‍‍

results in:

func = (a, b, c) => console.log(a, b, c)
interval = randomDelay()
params = [ 31, 32, 33 ]‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

When calling func we passed the parameters using the spread syntax,  i.e.

func(...params)‍‍‍‍‍‍‍‍‍‍

which passes the parameter array as individual parameters to the function, i.e.

func(31, 32, 33)‍‍‍‍‍‍‍‍‍‍

which ultimate calls

console.log(31, 32, 33)‍‍

Closing Remarks

This blog discusses an AppStudio implementation of setTimeout(). It was used as a way to give you a glimpse of some of the new ECMAScript 6 features, i.e. arrow functions, property shorthand and rest parameters and spread syntax which you can utilize in your AppStudio apps.

I plan to talk about Promises in ECMAScript 6 and AppStudio in a future blog. That blog will reuse the setTimeout() function and arrow functions introduced here.

In the meantime, please help us improve Promises in AppStudio by voting on fixing Promise chains bug https://bugreports.qt.io/browse/QTBUG-71329 and by voting on implementing async/await support in https://bugreports.qt.io/browse/QTBUG-58620

References

  • https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
  • http://es6-features.org/#ExpressionBodies
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
  • https://es6-features.org/#PropertyShorthand
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
  • https://bugreports.qt.io/browse/QTBUG-71329

Send us your feedback to appstudiofeedback@esri.com

Become an AppStudio for ArcGIS developer! Watch this video on how to sign up for a free trial.

Follow us on Twitter @AppStudioArcGIS to keep up-to-date on the latest information and let us know about your creations built using AppStudio to be featured in the AppStudio Showcase.

The AppStudio team periodically hosts workshops and webinars; please click on this link to leave your email if you are interested in information regarding AppStudio events.

2 Comments
PaulHaakma
Regular Contributor

Stephen Quan‌ thanks for pointing out the issue with promise chaining. I've just starting using promises in AppStudio 3.3 to will keep this in mind.

fyi I have upvoted that bug issue as you suggested.

StephenQuan1
Occasional Contributor III

Glad that it helped! Thanks for the upvote on the bug.