locked
local.readText() What am I doing wrong? RRS feed

  • Question

  • Hi

    I have this code:

                    WinJS.Application.local.readText('dboptions.json', 'not found').done(
                    function (data) {
                        console.log("options data: " + data);
                        if (data == undefined) {
                            gotOptions = false;
                            console.log("couldn't get options");
                        }
                        else {
                            //parse ready for passing to next page
                            dboptions = JSON.parse(data);
                            gotOptions = true
                        }
                    },
                    function (data) {
                        gotOptions = false;
                        console.log("couldn't get options");
                    }
                    );

    I expect the code to fulfil the promise and then proceed to the first function ('complete') if it gets the file contents, or to the second one ('error') if it fails. In fact it just jumps past both functions. However, if I laboriously step line by line through the WinJS code which executes the promise, I can see that the contents of the file are in fact acquired, and the first function ('complete') is eventually entered. It seems a bit weird that the code for the promise is not executed unless I explicitly step into and through it.

    Any ideas?

    Saturday, January 26, 2013 4:01 PM

Answers

  • Maybe I didn't undersand your question right, but what's wrong with your explanation? That function call is asynchronous. It works like that :

    If you put some breakpoints i.e. in onComplete, onError and at the line after the readText call, you'll see indeed that the latest breakpoint will be hit before those in onComplete or onError.

    // --> Some lines of code before your async call
    
    // Your async call
    WinJS.Application.local.readText('dboptions.json', 'not found').done(
        function(value) {
            //onComplete
        },
        function(error){
            //onError
        },
        function(progress){
            //onProgress
        });
    
    // The code here continues executing directly after the async call started.
    // --> Some other lines of codes that may be executed before the async call fulfilled.
    If you want the 'some other lines' to be proceed after the text is read, you should consider putting the code in the onComplete function.


    http://www.renauddumont.be

    • Proposed as answer by Can Bilgin Sunday, January 27, 2013 8:10 AM
    • Marked as answer by munder Sunday, January 27, 2013 12:12 PM
    Saturday, January 26, 2013 8:55 PM
  • The thing is that you can return something in your optionsDone, which will be used in the next then call.

    Here is a short piece of code I wrote for you. You should past-it somewhere and put a breakpoint in each call back to really understand what is the result.

        WinJS.xhr({ url: "http://www.microsoft.com" })
            .then(function (microsoftResult) {
                // Here we receive the response, as excepted.
                // So what do we do here? We could try another asynchronous call,
                // or just return a simple value.
                // Let's return the url that we want to fetch in the next call :
                return "http://dev.windows.com";
            }).then(function (devWindowsUrl) {
                // The devWindowsUrl simply contains the value that we returned in the previous call.
                // Now let's try another Async call, and instead of using callbacks here, let's just return the promise !!
                return WinJS.xhr({ url: devWindowsUrl });
            }).then(function (devWindowsResult) {
                // When we are here, you can see that devWindowsResult doesn't contain a promise.
                // It contains the actual value that we wanted to retrieve from the previous async call.
                // That's the magic :)
    
                // Now let's throw an exception by calling a non-existing function
                return devWindowsResult.callNonExistingFunction();
            }).then(function (nonExistingResult) {
                // We don not hit this breakpoint
                return "wow, does it really exist?";
            }, function (nonExistingError) {
                // Instead, we are here, because the promised is fulfilled with an error
                // Now let's return something nice, because we managed to handle the error.
                return "that function didn't exist but it's okay, we handled the exception!";
            }).then(function (errorHasBeenHandledResult) {
                // then, everything continues normally
                return "happy :)";
            }).done(function (result) {
                // and at the end you should end up with a done function.
                // The difference is that if there is an exception thrown, 
                // within this function, the error will be actually thrown
    // and not just passed as an argument in a next callback.
    // The error is thrown asynchronously, so you should ensure // you catch the last-chance exception at the app-level. return result.callANonExistingMethod(); }, function (error) { // Here we can eventually handle an error in the previous 'then' error handling callback. var resultError = error; });

    By the way, to make sure you catch the asynchronous exceptions, you can add an event handler like this :

        var app = WinJS.Application;
        app.onerror = function (error) {
            //Log the last-chance exception 
        };


    http://www.renauddumont.be


    • Edited by RenaudDumontMVP Sunday, January 27, 2013 1:20 PM
    • Marked as answer by munder Thursday, April 11, 2013 10:40 PM
    Sunday, January 27, 2013 1:17 PM

All replies

  • Maybe I didn't undersand your question right, but what's wrong with your explanation? That function call is asynchronous. It works like that :

    If you put some breakpoints i.e. in onComplete, onError and at the line after the readText call, you'll see indeed that the latest breakpoint will be hit before those in onComplete or onError.

    // --> Some lines of code before your async call
    
    // Your async call
    WinJS.Application.local.readText('dboptions.json', 'not found').done(
        function(value) {
            //onComplete
        },
        function(error){
            //onError
        },
        function(progress){
            //onProgress
        });
    
    // The code here continues executing directly after the async call started.
    // --> Some other lines of codes that may be executed before the async call fulfilled.
    If you want the 'some other lines' to be proceed after the text is read, you should consider putting the code in the onComplete function.


    http://www.renauddumont.be

    • Proposed as answer by Can Bilgin Sunday, January 27, 2013 8:10 AM
    • Marked as answer by munder Sunday, January 27, 2013 12:12 PM
    Saturday, January 26, 2013 8:55 PM
  • Thank you for your help. I'm afraid I keep failing to wrap my elderly mind around this asynchronous stuff. So now I have:
                    WinJS.Application.local.readText('dboptions.json', 'not found').then(optionsDone, optionsFailed).then(doMoreStuff);
                    function optionsDone(data) {
                        console.log("options data: " + data);
                        if (data == undefined) {
                            gotOptions = false;
                            console.log("couldn't get options");
                        }
                        else {
                            //parse ready for passing to next page
                            dboptions = JSON.parse(data);
                            gotOptions = true
                        }
                    }
                    function optionsFailed(data) {
                        gotOptions = false;
                        console.log("couldn't get options");
                    }
                    function doMoreStuff(){
                        //do some more stuff here
                    }
    Does that look to you like the right way to do it? It works just fine. My only concern is that I seem to be ending up with functions within functions within functions and a great crash of braces and parentheses. For example, within 'doMoreStuff' I need to read another file and so again have a 'complete' function, an 'error' function and a 'doEvenMoreStuff' function. It's starting to look like it could be a PITA to maintain. I hope you don't mind my asking if you could suggest a better approach. Thanks.
    Sunday, January 27, 2013 12:19 PM
  • The thing is that you can return something in your optionsDone, which will be used in the next then call.

    Here is a short piece of code I wrote for you. You should past-it somewhere and put a breakpoint in each call back to really understand what is the result.

        WinJS.xhr({ url: "http://www.microsoft.com" })
            .then(function (microsoftResult) {
                // Here we receive the response, as excepted.
                // So what do we do here? We could try another asynchronous call,
                // or just return a simple value.
                // Let's return the url that we want to fetch in the next call :
                return "http://dev.windows.com";
            }).then(function (devWindowsUrl) {
                // The devWindowsUrl simply contains the value that we returned in the previous call.
                // Now let's try another Async call, and instead of using callbacks here, let's just return the promise !!
                return WinJS.xhr({ url: devWindowsUrl });
            }).then(function (devWindowsResult) {
                // When we are here, you can see that devWindowsResult doesn't contain a promise.
                // It contains the actual value that we wanted to retrieve from the previous async call.
                // That's the magic :)
    
                // Now let's throw an exception by calling a non-existing function
                return devWindowsResult.callNonExistingFunction();
            }).then(function (nonExistingResult) {
                // We don not hit this breakpoint
                return "wow, does it really exist?";
            }, function (nonExistingError) {
                // Instead, we are here, because the promised is fulfilled with an error
                // Now let's return something nice, because we managed to handle the error.
                return "that function didn't exist but it's okay, we handled the exception!";
            }).then(function (errorHasBeenHandledResult) {
                // then, everything continues normally
                return "happy :)";
            }).done(function (result) {
                // and at the end you should end up with a done function.
                // The difference is that if there is an exception thrown, 
                // within this function, the error will be actually thrown
    // and not just passed as an argument in a next callback.
    // The error is thrown asynchronously, so you should ensure // you catch the last-chance exception at the app-level. return result.callANonExistingMethod(); }, function (error) { // Here we can eventually handle an error in the previous 'then' error handling callback. var resultError = error; });

    By the way, to make sure you catch the asynchronous exceptions, you can add an event handler like this :

        var app = WinJS.Application;
        app.onerror = function (error) {
            //Log the last-chance exception 
        };


    http://www.renauddumont.be


    • Edited by RenaudDumontMVP Sunday, January 27, 2013 1:20 PM
    • Marked as answer by munder Thursday, April 11, 2013 10:40 PM
    Sunday, January 27, 2013 1:17 PM