Windows 8.1 : let’s discover the Scheduler of #WinJS

, , 2 Comments

WinJSSchedulerWindows 8.1 comes with a new feature in the WinJS SDK : a scheduler. Let’s see what it is and how to use it!

In Windows 8, every job is nearly done as soon as you execute it. You could play with the msSetImmediate function but it was still a little mode “hack” than “code”.

With Windows 8.1, the SDK introduce a scheduler used by the whole WinJS framework. This scheduler helps you to define what is important (animations, visual feedback, manage user input) from what can be delayed (background work, data processing not used immediatly).

The goal is to let you build application which reacts immedialty to the user will.

What’s in it ?

Everything lives in the WinJS.Utilities.Scheduler namepsace and is written in javascript.
This namespace is often shortcuted “Scheduler” or “S” in the Microsoft samples.
[js]var S = WinJS.Utilities.Scheduler;[/js]

There is 4 importants objects to know :

  • WinJS.Utilities.Scheduler: the main namepsace with a lot of static function which lets you start and manage jobs
  • WinJS.Utilities.Scheduler.IJob : everything thing is a job. When you start a task/work using the scheduler, it returns you an IJob object on which you can call management methods.
  • WinJS.Utilities.Scheduler.IJobInfo : information passed to your work-function when executed.
  • WinJS.Utilities.Scheduler.IOwnerToken : you want to be the owner of a task and manage a group of jobs then use this.

How to use it (101) ?

Launching a job is as simple as providing a function :
[js]
var job = WinJS.Utilities.Scheduler.schedule(function willBeExecuted(){

//work to be done
});
[/js]

There is some optional parameters that can be set too : a priority (default is WinJS.Utilities.Scheduler.Priority.normal.), a this parameter which will be set when the function is executed and name (useful when debugging):
[js]
var whoAmI = {};
var job = WinJS.Utilities.Scheduler.schedule(function willBeExecuted(){

//work to be done
} , WinJS.Utilities.Scheduler.Priority.normal, whoAmI, " I am the job name" );
[/js]

The returned object is a IJob object and you can call some function on it to cancel it’s scheduling, pause it, resume it and have some information like the name, the priority, the owner, etc.
[js]
//create a job
var job = WinJS.Utilities.Scheduler.schedule( /* …*/);
//pause the job
job.pause();

//resume it in 5 secs
WinJS.Promise.timeout(5000).then(job.resume);

//reads the name of the job
var name = job.name;
[/js]

IJobInfo and yielding

In this case “yielding” means “let other task more important than me start and do their job while I am executing and pause me”.
Let’s assume that you have a job which takes 10 seconds to be done and that you can split it in 10 parts.
Then you can launch the job with the scheduler, do the first part and tells it : do something else (other jobs with higher priority) if necessary then call me back. The Scheduler will then manage this process for you.

When your job is executed, a parameter is actually provided and it implements the IJobInfo interface. This jobInfo object has 2 important functions and 1 important field :

  • setPromise: calling it providing a function tells the scheduler to wait for this promise before to call you back. If you need to download locally an internet resource, the Scheduler does not need to call you before and you can set a promise to wait for the download to be done.
  • setWork : calling it providing a function tells the scheduler which function to call when it wants to continue your processing (after the execution of more importants tasks).
  • shouldYield : read this to know if the function should yield : if true, you set the next function to call using the setWork function and you returns. If false, you do your job.

So how do we implement this feature ? By creating a processing function which will process each part in a loop. At each cycle, we will check if we have to yield. If so, we tells the scheduler to call us back when it wants to restart our process. If the process is done (10 parts processed) then we just returns.

Here is how I will implement this “10 parts processing”.
[js]var partProcessed = 0;

function executeYieldingTask() {

// schedule some work
S.schedule(function myScheduledJob(jobInfo) {

//Process the 10 parts
while (partProcessed < 10) {

//check if I have to yield :new job with higher priority
// may have been scheduled
if (jobInfo.shouldYield) {

//tells the Scheduler to execute myScheduledJob
// when it’s done executing higher priority task
jobInfo.setWork(myScheduledJob);

//we yield so we exit the ‘process loop’
break;

}
else {
/* process the part partProcessed */
partProcessed = partProcessed + 1;
}
}
}, S.Priority.idle);
}

[/js]

The IOwnerToken interface and how to use it

IOwnerToken is an interface which represents the owner of a job. By owner it means “master” : the one who controls and manage it.
A token can be set to multiple jobs at once and there is one function on this interface : cancelAll. This function simply cancel all the jobs owned by the token.

To create a token, you have to call the createOwnerToken function. You can then assign it to created job.
[js]
//create a token
var ownerToken = WinJS.Utilities.Scheduler.createOwnerToken();

//create jobs
var job1 = WinJS.Utilities.Scheduler.schedule( /* …*/);
var job2 = WinJS.Utilities.Scheduler.schedule( /* …*/);

//Be in control
job1.owner = ownerToken ;
job2.owner = ownerToken ;

//Cancel the jobs at once :
ownerToken.cancelAll();
[/js]

This token is then really useful when you want to manage a group of jobs at once. Create an owner, if the user do something else, goes to another page : you cancel all the task at once and retrieve some CPU juice.

Some useful functions

Now let’s discover some useful functions when playing with jobs and the scheduler.

  • requestDrain : use this function if you want to be sure that all scheduled jobs at a given priority are over. Simply pass the targeted priority, it returns a promise which can be use to know the completion of the “error state” of the queue processing
  • retrieveState : you need to dump the schedule queue for debug purpose ? Use this function :). It dumps the name, the id, the priority of the tasks, etc.
  • schedulePromiseXXX : there is a lot of functions with similar names(schedulePromiseAboveNormal, etc.). These functions takes a promise as a parameter. It assures that the completion/error handler is processed on the scheduler with the given priority. If you want a completion handler tob be processed as soon as the promise is done, then use schedulePromiseHigh.

Here are some code example :
[js]
//requestDrain example
var drainPromise = WinJS.Utilities.Scheduler.requestDrain(priority, name);

drainPromise.done(
function complete(){console.log("queue drained");},
function error(){ });

//retrieveState example :
var S= WinJS.Utilities.Scheduler;
S.schedule(function () {/* */ }, S.Priority.aboveNormal,null,"a task name");
S.schedule(function () {/* */ }, S.Priority.idle,null, "infinite square name");
S.schedule(function () {/* */ }, S.Priority.belowNormal,null,"another task name");

var state = WinJS.Utilities.Scheduler.retrieveState();
/*
state looks like this :
Jobs:
id: 22, priority: aboveNormal, name: a task name
id: 24, priority: belowNormal, name: another task name
id: 23, priority: idle, name: infinite square name
Drain requests:
None
*/

//schedulePromiseXXX example
var dldPromise = WinJS.xhr({url:’www.infiniteSquare.com’});
WinJS.Utilities.Scheduler.schedulePromiseHigh(dldPromise)
.then(function(xhrResult){
/* process interesting content */
});

[/js]

Regards.

 

2 Responses

  1. rampratap

    03/08/2014 21 h 09 min

    In my windows store app WinJS.Utilities.Scheduler is null, i have winjs library for javascript 1.0 referenced in the project, i have windows 8.1, VS 2012. Any idea why WinJS.Utilities.Scheduler is null?

Comments are closed.