Paul Michaels
Paul Michaels

Reputation: 16695

WinJS Promise then erroring

After some experimentation, I've ended up with the following code, trying to replicate the C# await functionality:

var promise = new WinJS.Promise(MyFunc())
    .then(function () {
        // Second function which uses data set-up in the first
        MyFunc2();
    });

'MyFunc()' executes correctly, but 'MyFunc2()' does not, and the program crashes. What am I misunderstanding about the Promise object?

(This is using Windows 8)

EDIT:

The full code for MyFunc() is now as follows:

function MyFunc() {
    var foldername = "Folder";
    var filename = "readme.xml";

    var promise = Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync(foldername).then(function (folder) {
        folder.getFileAsync(filename).then(function (file) {
            var loadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings;
            loadSettings.prohibitDtd = false;
            loadSettings.resolveExternals = false;
            Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file, loadSettings).then(function (doc) {
                dataText = doc.getXml();
                xmlDoc = doc;
            }, function (error) {
                output.value = "Error: Unable to load XML file";
                output.style.color = "red";
            }, function (error) {
                output.value = "Error: Unable to load XML file";
                output.style.color = "red";
            })
        })
    });

    return promise;
};

The result now is that 'MyFunc2()' executes before 'MyFunc()' completes. `MyFunc2() uses the global variable xmlDoc, which is therefore undefined at that time.

Upvotes: 3

Views: 1420

Answers (2)

Raymond Chen
Raymond Chen

Reputation: 45173

You should chain all the promises together and then wait on the final promise.

function MyFunc() {
    var promise = Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync(foldername).then(function (folder) {
        return folder.getFileAsync(filename);
        }).done(function (file) {
            var loadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings;
            loadSettings.prohibitDtd = false;
            loadSettings.resolveExternals = false;
            return Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file, loadSettings);
        }).then(function (doc) {
            dataText = doc.getXml();
            xmlDoc = doc;
            return doc; // whatever the result is
        }, function (error) {
            output.value = "Error: Unable to load XML file";
            output.style.color = "red";
        });
    return promise;
}

Then you can chain on the promise returned by MyFunc:

var promise = MyFunc().then(function(doc) { MyFunc2(...); });

Upvotes: 3

Paul O.
Paul O.

Reputation: 1176

All right, given the edit, you will have to use a slightly different approach. You will need to make MyFunc() actually return the promise variable you are creating. This will allow you to chain MyFunc to MyFunc2. So you would do something like this:

var promise = Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync(foldername).then(function (folder) {
        folder.getFileAsync(filename).done(function (file) {
            var loadSettings = new Windows.Data.Xml.Dom.XmlLoadSettings;
            loadSettings.prohibitDtd = false;
            loadSettings.resolveExternals = false;
            Windows.Data.Xml.Dom.XmlDocument.loadFromFileAsync(file, loadSettings).then(function (doc) {
                dataText = doc.getXml();
                xmlDoc = doc;
            }, function (error) {
                output.value = "Error: Unable to load XML file";
                output.style.color = "red";
            });
...
return promise;

Assuming that's the only promise in MyFunc(). If not, you can either chain all the promises together, or put them all in an array and return, for example, WinJS.Promise.join(promiseArray).

Now that you are returning a promise from MyFunc(), you can use then to chain it.

var promise = MyFunc().then(function () {
    // Second function which uses data set-up in the first
    MyFunc2();
});

If MyFunc2 also contains async code, you could return those promises as well, and keep chaining as long as you needed to.

var promise = MyFunc().then(function () {
    // Second function which uses data set-up in the first
    return MyFunc2();
}).then(function () {
    //And on and on...
});

Upvotes: 1

Related Questions