Handling Asynchronicity
All functions in the ACtl API are asynchronous, i.e. they don't return their result directly.
Instead, they return a Promise object which, in turn, gives the function's result.
The reason for why it has to be this way is a long story, but if you are curious, you can learn more at
Asynchronous JavaScript.
In order to deal with these Promise objects, Javascript provides the await keyword
which makes the use of promises feel like a walk in park.
Observe:
//Get the content of "sitemap.txt"
let fileContent = await ACtl.getFile('http://autocontrol.app/sitemap.txt') ;
//For each URL in the file
for( let pageUrl of fileContent.split('\n') ){
//Open the URL in a new tab
let newTabId = await ACtl.openURL(pageUrl, {rightOf: '#currentTab'}) ;
//And then pin that tab
ACtl.setTabState(newTabId, 'pinned') ;
}
The await keyword, used in the above script, takes the Promise object returned by the function on its right side and turns it into the function's result.
This makes the use of asynchonous functions trivial, as if they were regular functions.
await will do its magic wherever you put it. Consider this alternative form of the previous code:
//Call the function without "await" and store its returned value
let promiseObj = ACtl.getFile('http://autocontrol.app/sitemap.txt') ;
//Now use "await" to turn the promise into its result
let urls = (await promiseObj).split('\n') ;
The return of ACtl.getFile (which is a Promise object) is stored in a variable, and then that variable is passed to await,
which in turn gives back the file content.
i.e. a Promise object can be passed to await either directly from a function or as a variable or as any expression that results in a Promise.
All that matters is that a Promise goes into await and the Promise's result gets out.
And, since await is actually an operator, it can be used in the middle of any expression, as shown in the code example above.
It has the same precedence of the typeof operator.
But, what if we don't use await to call an asynchronous function?
This is no problem, the function is executed anyway, but asynchronously.
i.e. the script will continue without waiting for the function to finish.
Notice the lack of await before the ACtl.setTabState function in the first code example above.
Since we don't need to wait for the tab to be pinned, there's no need for await in that case.
The await operator "awaits" for the Promise object to be fulfilled, and then it gives the result back.
If we don't need a function's result or if we don't need to wait for it to complete, we can call the function without await.
Creating your own functions
One detail to keep in mind about await is that it can only be used inside async functions.
This is a restriction of the language itself, but not really a problem.
Let's say you want to create a function for replacing text in a file, like this:
function fileReplaceStr(filePath, search, replace)
{
let fileCont = await ACtl.getFile(filePath) ; //ERROR: "await" can't be here
fileCont = fileCont.replace(search, replace) ;
await ACtl.saveFile(filePath, fileCont) ; //ERROR: neither here
}
The code above will not work because the fileReplaceStr function is not declared as async. So, any use of await inside it, will be a syntax error.
The solution is simple, declare the function as aynchronous by prepending async to its declaration, and problem solved.
async function fileReplaceStr(filePath, search, replace)
{ //now we can use "await" in here
}
Now your function is asynchronous, so you can call it with await if you want to wait for it to finish, or without it if you don't.
await fileReplaceStr('C:/someFile.txt', 'foo', 'bar') ;
alert(`This message will appear once the replacement is done`) ;
But wait... if await can only be used inside async functions, then
How is it possible that the first example at the begining of this page works at all?
That example does work, indeed. And the reason is that AutoControl automatically puts the script
inside an async function. This way you can use the await operator without worrying about that detail.
This also makes it possible to use the return statement inside a script,
so you can end your scripts easily from any point with a simple use of the return statement.
Further reading:
Making asynchronous programming easier with async and await.