0

When using the asynchronous callback in e.g. file API in node or native functions with callbacks in cordova, you get code with really a lot of nested function definitions and argument lists that expand over many lines, making it quite hard to read.

Example: Get a file via HTTP and write it to a local file in cordova taken from https://cordova.apache.org/blog/2017/10/18/from-filetransfer-to-xhr2.html

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fs) {
    console.log('file system open: ' + fs.name);
    fs.root.getFile('bot.png', { create: true, exclusive: false }, function (fileEntry) {
        console.log('fileEntry is file? ' + fileEntry.isFile.toString());
        var oReq = new XMLHttpRequest();
        // Make sure you add the domain name to the Content-Security-Policy <meta> element.
        oReq.open("GET", "http://cordova.apache.org/static/img/cordova_bot.png", true);
        // Define how you want the XHR data to come back
        oReq.responseType = "blob";
        oReq.onload = function (oEvent) {
            var blob = oReq.response; // Note: not oReq.responseText
            if (blob) {
                // Create a URL based on the blob, and set an <img> tag's src to it.
                var url = window.URL.createObjectURL(blob);
                document.getElementById('bot-img').src = url;
                // Or read the data with a FileReader
                var reader = new FileReader();
                reader.addEventListener("loadend", function() {
                   // reader.result contains the contents of blob as text
                   // this could in fact contain even more function definitions
                });
                reader.readAsText(blob);
            } else console.error('we didnt get an XHR response!');
        };
        oReq.send(null);
    }, function (err) { console.error('error getting file! ' + err); });
}, function (err) { console.error('error getting persistent fs! ' + err); });

These are 4 nested function definitions. And, even harder to read - how to detect which error handler belongs to which function call.

Doe anyone know a clearer way to write this? Are there any best practice patterns?

Peter T.
  • 2,927
  • 5
  • 33
  • 40
  • HI! Please read through the [help], in particular [*How do I ask a good question?*](/help/how-to-ask), [*What types of questions should I avoid asking?*](/help/dont-ask), and [*What topics can I ask about here?*](/help/on-topic) If you're asking for help improving working code, this may be a better fit over at https://codereview.stackexchange.com, but be sure to take their [tour](https://codereview.stackexchange.com/tour) and read their [help](https://codereview.stackexchange.com/help) first, particularly [*What topics can I ask about here?*](https://codereview.stackexchange.com/help/on-topic) – T.J. Crowder Sep 27 '18 at 12:16
  • 1
    Why not `promise.then(someFunction).then(anotherFunction).catch(errorHandling)`? If you have big functions that means you'd still have that chain less readable but you can always define the functions elsewhere and just pass a reference. – VLAZ Sep 27 '18 at 12:17
  • That said: Look into [promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) and [`async`/`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function). – T.J. Crowder Sep 27 '18 at 12:17
  • One of the ways to do avoid callbacks is either to use `promises` or `async-await` syntax – Oleg G Sep 27 '18 at 12:17
  • 1
    If this is yours and proper working code, please consider to post to [Code Review](https://codereview.stackexchange.com/). I think you're asking for that. – Mario Santini Sep 27 '18 at 12:18
  • 1
    The best practice is to use promises instead of callbacks that are expected to be called once. Promises were introduced to eliminate nested callbacks (also known as 'callback hell') where possible. A lot of libraries have promisified counterparts, including https://github.com/markmarijnissen/cordova-promise-fs – Estus Flask Sep 27 '18 at 12:18
  • @estus thank you very much, cordova-promise-fs was the hint I was looking for! – Peter T. Nov 15 '18 at 14:25

0 Answers0