1

おそらく複数の非同期コールバックの状況を含むもつれに陥りました。

populatePageArea() という JavaScript 関数があります。

populatePageArea 内では、この配列のような変数 (pages と呼ばれる) を他のコードの間でトラバースします。

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...
}

addToPagesArea 関数内で、HTML 5 の FileAPI を使用して、他のコードの中でドラッグ アンド ドロップされたファイルをプレビューしました。

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..
}

そのため、ファイルをプレビューするたびに、ファイルの寸法を計算しようとしました。

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);

}

calculateRatio に見られるpageSizesは、配列のようなタイプの変数であるグローバル変数です。

populatePagesArea が呼び出される前は、間違いなく空です。

状況は次のとおりです。

私のコードは次のとおりです。

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

しかし、プレビューされたすべての画像で calculateRatio が呼び出されていないと思うので、getMajorityPageSize が呼び出されると、pageSizes は常に空になります。

populatePagesArea が呼び出された後、すべての calculateRatio 関数が実行された後にのみ getMajorityPageSize がトリガーされるようにするにはどうすればよいpagesですか?

これは非同期コールバックだと思います。しかし、calculateRatio のような非同期コールバック関数を実行する必要があるオブジェクトの配列に対してそれを行う方法がわかりません。

4

1 に答える 1

1

簡単な解決策(変更を次のようにマークしました// ***

// ***
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();
}

後でより多くの非同期処理を行う場合のより良い解決策は、promisesを使用してコードをリファクタリングすることです。Promises は、体系的かつ組織的な方法で非同期プログラミングを処理するために設計された API です。より多くの非同期作業を行う場合は、生活がずっと楽になります。Promiseをサポートする無料のライブラリはたくさんありますが、主要なプレーヤーの 1 つはQ.jsです。

于 2012-11-27T13:16:59.700 に答える