locked
Handling errors in nested Promises

    Question

  • I am currently working on a bunch of convenience methods for file I/O and am not entirely sure I understand how to properly use WinJS.Promises correctly.

    In particular how error handling works with nested promises. The Chaining Promises page says that you should prefer

    aAsync()
        .then(function () { return bAsync(); })
        .then(function () { return cAsync(); })
        .done(function () { finish(); });


    over this

    aAsync().then(function () {
        bAsync().then(function () {
                cAsync().done(function () { finish(); });
        })
    });


    with the explanation 'You should prefer flat promise chains to nested ones. The formatting of promise chains makes them easier to read, and it's much easier to deal with errors in promise chains.'

    The problem is that I find completely flat promise chains impractical, especially when I want to create utility methods and so I'm trying to figure out how exactly error handling is done with nested promises.

    Here is an example of a method that I am working on.

    var pickFileAndReadBlob = function (picker) {
    	return new WinJS.Promise(function (complete, error) {
    		var file;
    		picker.pickSingleFileAsync()
    			.then(function (f) {
    				if (!f) {
    					complete();
    					return;
    				};
    				file = f;
    				return file.openReadAsync();
    			})
    			.then(function (stream) {
    				//throw 'error';
    				var blob = MSApp.createBlobFromRandomAccessStream(file.contentType, stream);
    				complete(blob);
    			})
    			.then(null, function (err) { error(err); });//add final then to get error from nested promises
    	});
    };

    The method takes a picker, lets the user select a file, then reads the file and creates a blob from the stream and finally calls complete with the blob. To use this you would call it like so:

    var picker = new Windows.Storage.Pickers.FileOpenPicker();
    picker.fileTypeFilter.replaceAll(['.txt']);
    
    pickFileAndReadBlob(picker).then(function(blob){
    	//do something
    },function(err){
    	//error has occurred
    });

    It took me a while to get this to work but after adding the empty .then() with only an error handler the method seems to report any errors correctly (just test by adding randomly placed 'throw' statements).

    My question is, is this how we are supposed to propagate errors in nested promises?

    Is there a simpler, cleaner way to write a method like this?


    Friday, March 23, 2012 4:31 AM

Answers