Scheduler API in Windows 8.1 and Visual Studio 2013

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Introduction

Hello again! Today I will talk about the new scheduler API, to manage and schedule tasks or jobs, present in Windows 8.1. This allows us to set the priority of each job so that system resources are more effectively used and responsiveness is improved. The Scheduler API forms part of WinJS.Utilities and is brand new.

Asynchronous Programming

In previous articles, I explained in detail the benefits of Asynchronous programming and what it is. The article can be found here. In case you haven’t read it yet, here is a small quote from it: “Asynchrony is crucial to any app that depends on certain tasks that may cause bottlenecks or block the rest of your program, better yet, freezing. So in fact, it makes applications respond quicker while running several tasks in the background.” Now that we know what Asynchronous programming is all about, let us move on to the new Scheduler API in Windows 8.1.

Scheduler API

The Scheduler API consolidates all work queues into a single queue with priority-based scheduling capabilities. This provides faster and more fluid applications. More details of the Scheduler API can be found here.

Our Project

Open Visual Studio 2013 Preview on Windows 8.1 Preview or Visual Studio 2013 RC on Windows 8.1 RTM, and start a new blank JavaScript Windows Store project entitled Schedule_JS.

“Wait! A JavaScript project? Hannes, are you sure it is not VB?”

“Yes, I am”

“But why?”

“Well, with this article I am trying to explain the Scheduler API, which forms part of WinJS.Utilities, and, it’s time for something different concerning the Windows 8 Store.”

Any other questions, No, right.

Design

Add four buttons to your default.html web page that was created automatically via the toolbox, or you could edit the HTML code directly. Your design should resemble Figure 1, and your code should resemble the following code segment.

default.html Body code :

<body>
<p>Scheduling Tasks</p>
<button id="pause">Pause Tasks</button>
<button id="cancel">Cancel Tasks</button>
<button id="yield">Yield Job Within Task</button>
<button id="drain">Drain Tasks</button>
</body>

Our Design
Figure 1 – Our Design

Coding

Now that the design is out of the way, we can concentrate on the coding. The first piece of business would be to cover how to schedule jobs and what jobs are. A job is simply a task that wants to run at any given time. This can be anything, but, the whole purpose of job scheduling is so that your app doesn’t freeze when it has to do a lot of work; so the best would be to take time consuming tasks and prioritize them. You should already have an idea of which functions in your programs will take some time and which won’t – you should just set the desired priorities of each job. We schedule the tasks / jobs we want to run via the Scheduler API.

A note: Seeing the fact that this article makes use of JavaScript and HTML coding and references, make sure that you are indeed up to speed with all these technologies.

Scheduling Jobs

Scheduling work is as easy as passing the function that should do the desired task to the schedule method, and specifying the task’s priority. We first need to create the job(s) and then we can set their priorities. We also pass a function to each job so that each job runs separately. This is the beauty of Asynchronous programming. Here is a small example on creating a job:

 var JS_Scheduler = WinJS.Utilities.Scheduler; //Create Scheduler Object


function JS_Task() {
window.output("\nScheduling job");

//Schedule A Job
var Job = JS_Scheduler.schedule(function () {
window.output("Here I Can Do Whatever I Like"); //Give Some Work
}, JS_Scheduler.Priority.normal); //Set Priority

}

It looks more complicated than what it is! On the first line, we create the Scheduler object. This gets its capabilities from WinJS.Utilities.Scheduler. Next, we create a function named JS_Task. We then create a job. When and how this job will be run, depends on its priority, which in this case, is Normal. Here is a complete list of available Priorities.

IJob Interface

With the use of the IJob interface, we can Pause, Yield, Resume, Drain and Cancel jobs. Here is more information on it.

Pausing jobs

In your project, add a new JavaScript file by clicking on Project, Add New File and select JavaScript File from the list, as shown in Figure 2, and give it a name such as pause.js.

Adding a new JavaScript file
Figure 2 – Adding a new JavaScript file

Inside Pause.js enter the following code:

(function () {
"use strict";

//Are We On Correct WebPage?
WinJS.UI.Pages.define("default.html", {
ready: function (element, options) {
document.getElementById("pause").addEventListener("click", JS_pause, false); //Add Listener
WinJS.Navigation.addEventListener("beforenavigate", beforeNavigate);
}
});

var JS_Scheduler = WinJS.Utilities.Scheduler;//Create Scheduler Object

function beforeNavigate(eventInfo) {
//Pause Task
if (WinJS.Navigation.location === pageLocation) {

JS_pause();

}
}

//Function To Be Run When Cancel Button Is Clicked
function JS_pause() {

window.output("\nScheduling job to pause");

// Schedule A Job To Be Paused
var JobToBePaused = JS_Scheduler.schedule(function () {
window.output("Here I Can Do Whatever I Like");
}, JS_Scheduler.Priority.normal);

var SomeOtherJob = JS_Scheduler.schedule(function () {
window.output("Here I Can Do Some Other Stuff");
}, JS_Scheduler.Priority.normal);

window.output("\nI'm Tired Now, May I Take A Break?");

JobToBePaused.pause(); //Pause Job


}
}
)();

A lot happens here! First, we have to determine which page we need this script to run on. In this case, I have kept it at default.html. You could of course have added another HTML file for better organization of your code – but I’ll leave that decision up to you. Then, we have to identify the button we want to use with this JavaScript code. In this case we need the pause button and we need to add a listener to it. A listener is basically the same as an event handler.

I have added another event called beforeNavigate. This event will trigger the pausing code, which is defined in the function named JS_pause.

JS_pause gives output on what we will do, then it creates the scheduler named JobToBePaused. I can let it do whatever I like, but this example just shows a simple message. I set its priority. I then create another job and pause the job I need to. Obviously this is just an example, but I think you’ll get the idea.

Resuming Jobs

To resume a task, you simple need to use:

JobToBePaused.resume

Cancelling Jobs Completely

Add another new JavaScript file to your project, as explained previously, name it cancel.js and enter the following code into it:

(function () {
"use strict";

//Are We On Correct WebPage?
WinJS.UI.Pages.define("default.html", {
ready: function (element, options) {
document.getElementById("cancel").addEventListener("click", JS_cancel, false);
}
});

var JS_Scheduler = WinJS.Utilities.Scheduler; //Create Scheduler Object

//Function To Be Run When Cancel Button Is Clicked
function JS_cancel() {
window.output("\nScheduling job to cancel");

//Schedule A Job To Be Cancelled
var JobToBeCanned = JS_Scheduler.schedule(function () {
window.output("Here I Can Do Whatever I Like"); //Give Some Work
}, JS_Scheduler.Priority.normal); //Set Priority

window.output("Had Fun? OK, Good Bye, I am Being Cancelled Now!");
JobToBeCanned.cancel(); //Cancel Job
}


})();

As you can see, it looks very similar to the previous code segment, we just cancel a job completely.

Yielding Jobs Within a Task

Add a new JavaScript File, name it yield.js and enter the following:

(function () {
"use strict";

//Make Sure We Have Correct Page
WinJS.UI.Pages.define("default.html", {
ready: function (element, options) {
document.getElementById("yield").addEventListener("click", JS_yield, false); //Add Listener
WinJS.Navigation.addEventListener("beforenavigate", beforeNavigate);
}
});

var JS_Scheduler = WinJS.Utilities.Scheduler; //New Scheduler Object
var Completed;

function beforeNavigate(eventInfo) {

if (WinJS.Navigation.location === pageLocation) {
//Do Necessary Work To Complete All Tasks
return;
}


if (eventInfo.detail.location === pageLocation) {
Completed = false; //Task Was Not Completed
return;
}
}



function JS_yield() {

//Function To Be Run When Yield Clicked
JS_Scheduler.schedule(function YieldWorker(YieldJobInfo) {
while (!Completed) {
if (YieldJobInfo.shouldYield) {

window.output("Yielding just temporarily"); //Wait A Bit
YieldJobInfo.setWork(YieldWorker);
break;
}
//Run Again
else {
window.output("Running idle yielding job again");
var start = performance.now();
//Do Complicated Task
}
}




})}});

The trick with yielding jobs within jobs is that you need to know which part of your function might consume most of the processor and time. Once you encounter a possible long task, you could yield it temporarily until something has completed and then resume it again.

Draining Jobs

Add another JavaScript file and name it appropriately. Add the following code to it in order to drain tasks:

(function () {
"use strict";

//Right Place?
WinJS.UI.Pages.define("default.html", {
ready: function (element, options) {
document.getElementById("drain").addEventListener("click", JS_drain, false); //Add Listener
}
});

var JS_Scheduler = WinJS.Utilities.Scheduler;

//Function To Run When Drain Button Clicked
function JS_drain() {
DrainJobBasedOnPriority(JS_Scheduler.Priority.belowNormal, "belowNormal");
}

//Function Called By JS_drain To Drain Priority Based
function DrainJobBasedOnPriority(JS_Priority, JS_PriorityName) {
window.output("\nScheduling job(s) to drain");

//Schedule Job To Not Be Drained
JS_Scheduler.schedule(function () {
window.output("Normal Priority Job Will Not Be Drained :)");
}, JS_Scheduler.Priority.normal);


//Schedule Job To Be Drained
JS_Scheduler.schedule(function () {
window.output("BelowNormal Priority Will Be Drained :(");
}, JS_Scheduler.Priority.belowNormal);


//Drain Job
window.output("Draining " + JS_PriorityName + " Priorities");
JS_Scheduler.requestDrain(priority).done(function () {
window.output("Done draining! I'm Done!");
}
);
}
})();

What happens here is: we create and schedule jobs like normal. We then request to drain the functions that run under the lowest priority. Why? To clean up resources and it is simply good housekeeping to let things go when they are not really used.

If you were to run your app now, nothing will happen! Why? Because we need to let our default.html file know about all the new JavaScript files we have added. Open default.html and enter the following just above the opening Body tag:

<script src="/js/default.js"></script>
<script src="pause.js"></script>
<script src="cancel.js"></script>
<script src="yield.js"></script>
<script src="drain.js"></script>

I am attaching a working sample project with this article, just in case you have missed a step or two.

Conclusion

There you have it! This was very nice and it is just one of the many new wonderful things to expect with VS 2013 and Windows 8.1. Keep an eye out for an upcoming article named New controls and control updates in Windows 8.1 and Visual Studio 2013. Until then, cheers!

About the Author: Hannes du Preez is a Microsoft MVP for Visual Basic for the fifth year in a row. He is a trainer at a South African-based company providing IT training in the Vaal Triangle. You could reach him at hannes [at] ncc-cla [dot] com.

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read