locked
Async operations inside Activation handler. Help.

    Question

  • Hi,

    I have to do 3+3 async operations(create/grab 3 files and read the data and load to array variables) inside app.addEventlistener of 'activated' handler.  Where exactly inside the  activation handler should I do these async operations?

        As stated in the ebook, How do I obtain the promise of the async operations and hand it off to setPromise? Pls can someone shed some light on the code structure, where and how the async operations(create ,get and readtextAsync) need to be done.

    (When I do file Async operations with then,done,  inside the WinJS.UI.processAll which is inside setPromise, the first page sometimes appears before the data is fully extracted from the file. I have implemented extended splashscreen as well).

    Thanks


    karthika

    Wednesday, May 8, 2013 4:18 AM

Answers

  • For simplicity, let's say that you'll just do this without an extended splash screen.

    First, create a function that returns a promise for your particular async chain that does the read/load process. That is, the sequence/chain would be something like:

    function openAndRead(fileId) {
        var promise = getFileAsync(fileId).then(function(file) {
            return file.readTextAsync();
        }).then(function (contents) {
            return someOtherAsyncOp(contents);
        });
    
    return promise;
    }
    

    Notice that we’re building the chain with thens because we want a promise as a result.

    In your activated handler, then, you’d call this three times to obtain three promises for each open/read operation:

    var p1 = openAndRead("file1");
    var p2 = openAndRead("file2");
    var p3 = openAndRead("file3");
    

    Without an extended splash screen, what you need to do is now combine these three promises along with the one from WinJS.UI.processAll (assuming you have WinJS controls on the extended splash screen). For this you can use WinJS.Promise.join:

    var uiPromise = WinJS.UI.processAll();
    var join = WinJS.Promise.join([p1, p2, p3, uiPromise]);
    

    And that’s the one you’d then hand to setPromise:

    args.setPromise(join);
    

    With this code, then, the default splash screen will not be removed until all four promises are fulfilled.

    Now if you want to use an extended splash screen while you’re waiting, then you’d just do setPromise(uiPromise) in the activated handler, then within the initialization of the extended splash screen you’re create the other three promises. Then you’d get the join of the three, call its done (since you’re at the end), and in that completed handler take down the extended splash screen:

    var join = WinJS.Promise.join([p1, p2, p3]);
    join.done(function () { 
        //Switch to your main page now as p1, p2, and p3 are all fulfilled.
    });
    

    In short, you need to (a) create individual promises for the operations you wish to complete, then (b) call WinJS.Promise.join with that list, then (c) place any work that’s dependent on those operations in the completed handler passed to the join’s done method.


    Kraig

    Author, Programming Windows 8 Apps with HTML, CSS, and JavaScript, a free ebook from Microsoft Press

    • Marked as answer by ArunKarthika Thursday, May 9, 2013 12:06 PM
    Wednesday, May 8, 2013 5:27 AM

All replies

  • Hi,

    My suggestion would be this :

    app.addEventListener("activated", function (args) { if (args.detail.kind === activation.ActivationKind.launch) { if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) { // Initialize the function to call data make all calls initialDataRetrievalTasks(); // Show the splash : e.g

    ExtendedSplash.show(splash); // So other stuff here .... args.setPromise(WinJS.UI.processAll()); } });


    - Girija

    Wednesday, May 8, 2013 4:55 AM
  • It doesn't work. The program control goes in different order (among async operations)and so sometimes, loads the page before all data is taken.


    karthika

    Wednesday, May 8, 2013 5:10 AM
  • For simplicity, let's say that you'll just do this without an extended splash screen.

    First, create a function that returns a promise for your particular async chain that does the read/load process. That is, the sequence/chain would be something like:

    function openAndRead(fileId) {
        var promise = getFileAsync(fileId).then(function(file) {
            return file.readTextAsync();
        }).then(function (contents) {
            return someOtherAsyncOp(contents);
        });
    
    return promise;
    }
    

    Notice that we’re building the chain with thens because we want a promise as a result.

    In your activated handler, then, you’d call this three times to obtain three promises for each open/read operation:

    var p1 = openAndRead("file1");
    var p2 = openAndRead("file2");
    var p3 = openAndRead("file3");
    

    Without an extended splash screen, what you need to do is now combine these three promises along with the one from WinJS.UI.processAll (assuming you have WinJS controls on the extended splash screen). For this you can use WinJS.Promise.join:

    var uiPromise = WinJS.UI.processAll();
    var join = WinJS.Promise.join([p1, p2, p3, uiPromise]);
    

    And that’s the one you’d then hand to setPromise:

    args.setPromise(join);
    

    With this code, then, the default splash screen will not be removed until all four promises are fulfilled.

    Now if you want to use an extended splash screen while you’re waiting, then you’d just do setPromise(uiPromise) in the activated handler, then within the initialization of the extended splash screen you’re create the other three promises. Then you’d get the join of the three, call its done (since you’re at the end), and in that completed handler take down the extended splash screen:

    var join = WinJS.Promise.join([p1, p2, p3]);
    join.done(function () { 
        //Switch to your main page now as p1, p2, and p3 are all fulfilled.
    });
    

    In short, you need to (a) create individual promises for the operations you wish to complete, then (b) call WinJS.Promise.join with that list, then (c) place any work that’s dependent on those operations in the completed handler passed to the join’s done method.


    Kraig

    Author, Programming Windows 8 Apps with HTML, CSS, and JavaScript, a free ebook from Microsoft Press

    • Marked as answer by ArunKarthika Thursday, May 9, 2013 12:06 PM
    Wednesday, May 8, 2013 5:27 AM
  • Thanks again, Kraig. It works fine when I implemented as mentioned above, with extended splash screen.

    Just one thing I don't understand,  When I keep debug points,  I see the program control goes to

    "setPromise(uiPromise)" first and then only goes inside the, then's  function.(Meaning "readtext" and  "function(contents)" above).  then navigates to the home page. Is this order fine?


    karthika

    Wednesday, May 8, 2013 11:59 PM
  •  

    One more thing, I am doing the "WinJS.Navigation.navigate (Application.navigator.home);"   from inside the extended splash screen's show function, after finishing the promises there.   Is that okay too?


    karthika

    Thursday, May 9, 2013 12:06 AM
  • Yes, this is a tricky thing to understand about async functions and promises at first, but trust me, you'll get used to it.

    What you'll see in any promise chain is that the first call happens, followed by all the subsequent then/done's but none of the completed handlers given to those functions will be called unless the promise's value is already known. In the purely async case, this means that none of those handlers are called as part of processing then/done. They'll all be called later as the promises are fulfilled.

    In other words, if you remove the completed handlers from the code and just look at the remaining structure, you'll see something like asyncOp().then().then().then().then().done(), which, like any series of method calls, all happen sequentially (and synchronously). Arguments to these functions are, of course, evaluated as part of the process, but in each case you're simply passing a function object to each. So the function object is there, but that function isn't actually called when the value isn't already known. (Again, if the promise's value is known, it will synchronously call the completed handler).

    So the order that you're seeing things happening is expected. The key thing in all such cases is that any code you need to execute once the async operation has completed and returned results is what you have to put into your completed handler. If you put it outside that handler, then the async op will not necessarily be finished. For example, if you try to access a WinJS control before WinJS.UI.processAll is done, you'll likely end up with null objects because those controls aren't yet instantiated.

    Thursday, May 9, 2013 5:34 AM
  • Yes, that's no problem. The navigate call just starts the process of loading up the specified page control, and because you're waiting until your other promise is completed, then you won't start that process until you know it's right.

    Thursday, May 9, 2013 5:36 AM