简体   繁体   中英

multiple asynchronous callbacks javascript how do I resolve this?

I got myself into a tangle which probably involves multiple asynchronous callback situations.

I have a javascript function called populatePageArea()

Inside populatePageArea it traverses through this array-like variable called pages amongst other code.

function populatePagesArea() {
  // there was some code before the for loop

  for (var i=0, l=pages.length; i<l; i++) {    
    addToPagesArea(pages[i], "");   
  }

  // some code after...
}

Inside addToPagesArea function, I used the FileAPI from HTML 5 to preview the drag'n dropped files amongst other code.

function addToPages(file, front) {
  // there was some code before..
  reader = new FileReader();
  reader.onload = (function (theDiv) {
    return function (evt) {
      var backgroundimage = "url(" + evt.target.result + ")";
  theDiv.css("background-image", backgroundimage);
      var sizeSettings = getSizeSettingsFromPage(file, calculateRatio);

};

  }(imageDiv));

  // step#3 execute file reader
  reader.readAsDataURL(file);
  // there was some code after..
}

So every time I previewed the file, I also attempted to do some calculation on the dimensions of the file.

function getSizeSettingsFromPage(file, whenReady) {
    reader = new FileReader();
    reader.onload = function(evt) {
        var image = new Image();
        image.onload = function(evt) {
            var width = this.width;
            var height = this.height;
            var filename = file.name;
            if (whenReady) {
                whenReady(width, height, filename);
            }
        };
        image.src = evt.target.result; 
    };
    reader.readAsDataURL(file);

}
 function calculateRatio(width, height, filename) {

    var ratio = width/height;

    var object = new Object();
    object['height']    = width;
    object['width']     = height;
    object['ratio']     = ratio;
    object['size']      = 'Original';

    for (var size in SIZES) {
        var min = SIZES[size].ratio - 0.01;
        var max = SIZES[size].ratio + 0.01;

        if (ratio <= max && ratio >= min) {
            object['size'] = size;
        }
    }

    pageSizes.add(filename, object);

}

pageSizes as seen in calculateRatio is a global variable which is an array-like type of variable.

It is definitely empty BEFORE populatePagesArea gets called.

Here is the situation:

my code is:

populatePagesArea();
getMajorityPageSize(); // this acts on the supposedly non-empty pageSizes global variable

But because I think the calculateRatio has not been called on ALL the previewed images, the pageSizes is always empty when getMajorityPageSize is called.

how can i make sure that after populatePagesArea is called, getMajorityPageSize gets triggered ONLY after all the pages have undergone calculateRatio function?

I believe this is asynchronous callback. But I am not sure how to do it for an array of objects that will need to undergo an async callback function like calculateRatio.

The simple solution (I have marked my changes with // *** :

// ***
var totalPages;

function populatePagesArea() {
  // there was some code before the for loop

  // ***
  totalPages = pages.length;
  for (var i=0, l=pages.length; i<l; i++) {    
    addToPagesArea(pages[i], "");   
  }

  // some code after...
}

function addToPages(file, front) {
    // there was some code before..
    reader = new FileReader();
    reader.onload = (function (theDiv) {
      return function (evt) {
        var backgroundimage = "url(" + evt.target.result + ")";
        theDiv.css("background-image", backgroundimage);
        var sizeSettings = getSizeSettingsFromPage(file, calculateRatio);
        // *** Check to see if we're done after every load
        checkPagesReady();
      };

    }(imageDiv));

    // step#3 execute file reader
    reader.readAsDataURL(file);
    // there was some code after..
}

// *** Call getMajorityPageSize() here, only after all pages have loaded.
function checkPagesReady() {
    if (pageSizes.length >= totalPages)
        getMajorityPageSize();
}

The better solution if you're going to be dealing with more asynchronous things later on would be to refactor your code using promises . Promises is an API designed for dealing with asynchronous programming in a systematic and organized way. It'll make your life a lot easier if you're going to be doing more async work. There's a lot of free libraries that support promises, one of the major players is Q.js .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM