1
\$\begingroup\$

This code uses jQuery promises in combination with callbacks does the following:

  1. Saves Group UUID to server using storeGroupOnServer()
  2. Creates a DOM element for the group using createGroupDomNode()
  3. Creates child elements for each image, using createNewChildDomNode()

How can this be written more flat (avoiding the nesting), using .then()?

var groupPromise = groupInstance.promise();
var arrayOfFiles = groupInstance.files();

groupPromise.done(function(fileGroupInfo) {
    storeGroupOnServer(fileGroupInfo.uuid, function(groupid){

        createGroupDomNode(groupid, function(groupnode){

            $.each(arrayOfFiles, function(i, file) {
                file.done(function(fileInfo) {
                    createNewChildDomNode(fileInfo.cdnUrl, groupnode);
                });
            });
        });
    });
});

Step 1: storeGroupOnServer():

storeGroupOnServer = function(uuid, callback) {
    $.post('saveGroup.php', {uuid:uuid},
    function(data) {
        callback(data.groupid);
    },'json');
};

Step 2: createGroupDomNode():

createGroupDomNode = function(groupid, callback) {
    var cloner = $('#cloner');
    var newnode = cloner.clone(true);
    newnode.attr('id',groupid);
    newnode.removeClass('hide');
    cloner.after(newnode);
    callback(newnode);
}

Step 3: createNewChildDomNode():

function createNewChildDomNode(imgpath, groupdom){
    imgnode = $('<img/>').attr('src',imgpath);
    picnode = $('<picture/>').append(imgnode);
    $(groupdom).first().prepend(picnode);
}
\$\endgroup\$
2
  • \$\begingroup\$ Where is arrayOfFiles defined? \$\endgroup\$ Nov 17, 2018 at 23:36
  • \$\begingroup\$ @guest271314 Is defined outside the function, I've added it for completeness. \$\endgroup\$
    – bart
    Nov 18, 2018 at 21:49

1 Answer 1

1
\$\begingroup\$

You can substitute returning Promise objects from functions for using callbacks as parameters to function, to chain .then() and .catch(). Array.prototype.map() and Promise.all() can be substituted for jQuery.each() which does not await the fulfillment of Promise objects iterated.

Which requires returning the jQuery promise object from storeGroupOnServer

storeGroupOnServer = function(uuid, callback) {
    return $.post('saveGroup.php', {uuid:uuid},'json')
           .then(function(data) {
             return data.groupid;
           });
};

and returning a jQuery promise object of Promise from createGroupDomNode

createGroupDomNode = function(groupid, callback) {
    var cloner = $('#cloner');
    var newnode = cloner.clone(true);
    newnode.attr('id',groupid);
    newnode.removeClass('hide');
    cloner.after(newnode);
    return $.Deferred().resolve(newnode);
}

and awaiting <img> element load event

function createNewChildDomNode(imgpath, groupdom){
    return $.Deferred(function(dfd) {
             imgnode = $('<img/>')
                       .on("load", dfd.resolve)
                       .on("error", dfd.reject)
                       .attr('src',imgpath);
             picnode = $('<picture/>').append(imgnode);
             $(groupdom).first().prepend(picnode);
           }).promise();
}

For example

const data = {
  uuid: {
    1: 4,
    2: 5,
    3: 6
  }
};
const response = {
  4: "a",
  5: "b",
  6: "c"
};

const groupPromise = Promise.resolve(data.uuid[1]); // initial `Promise`
const arrayOfFiles = [Promise.resolve({
  fileInfo: {
    cdnUrl: 10
  }
}), Promise.resolve({
  fileInfo: {
    cdnUrl: 20
  }
}), Promise.resolve({
  fileInfo: {
    cdnUrl: 30
  }
})];

const storeGroupOnServer = (uuid) => {
  console.log({
    uuid
  });
  // `return` response `Promise`
  return Promise.resolve(response[uuid])
};

const createGroupDomNode = (groupid) => {
  console.log({
    groupid
  });
  // `return` `groupid`
  return Promise.resolve(groupid)
};
const createNewChildDomNode = (groupdom, {
  // destructure `cdnUrl` define as `imgpath`
  fileInfo: {
    cdnUrl: imgpath 
  }
}) => {
  console.log({
    imgpath,
    groupdom
  });
  // process `<img>` elements here
  // `return` resolved or rejected `Promise` 
  // at `load` or `error` event
  return Promise.resolve("done processing " + imgpath)
};
let handleFiles = (groupnode, file) => {
  console.log({
    groupnode,
    file
  });
  // handle each `file` `Promise`, pass `group` node to 
  // function passed to `.then()`
  return file.then(createNewChildDomNode.bind(null, groupnode))
};
const handleGroupDomNodes = (groupnode) => {
  console.log({
    groupnode
  });
  // use `Promise.all()`, `.map()` to process array of `Promise` objects
  return Promise.all(
    arrayOfFiles.map(handleFiles.bind(null, groupnode))
  )
};

groupPromise
.then(storeGroupOnServer)
.then(createGroupDomNode)
.then(handleGroupDomNodes)
.then(complete => console.log(complete)) // to illustrate chain completes
.catch(err => console.error(err)); // handle errors in chain

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.