2017-06-04 92 views
0

我有一個數據集,其中包含一個HTML5畫布的圖層數組。我使用fabric.js來管理畫布的所有元素。應該按順序加載圖層,形成不同的場景。我通過forEach循環遍歷數據集。 (編輯 - 進一步研究後,我看到for和for循環都是同步的)。在JavaScript中,您可以強制循環在當前迭代完成之前不處理下一次迭代嗎?

問題是,一旦代碼到達加載圖像的位置,異步行爲就會啓動並且進程跳轉到下一個循環以開始處理下一個圖層。正如你可以想象的那樣,這會導致圖層在畫布上出現亂序並最終失真的場景。

我一直在研究這個問題,並研究了幾個星期,沒有多少運氣。

有什麼辦法可以防止forEach循環(或for循環)在當前結束之前不啓動下一次迭代?

這裏是我的foreach循環代碼:

$.ajax({ 
    url: url, 
    method: "GET" 
}).done(function (data) { 
    data.forEach(function (data) { 
     switch (data.layer_type) { 
      case "texture": 
       { 
        addTexture(data) 
        break; 
       } 
      case "color": 
       { 
        addColor(data) 
        break; 
       } 
      case "room": 
       { 
        addBaseImg(data); 
        break; 
       } 
      case "decor": 
       { 
        addBaseImg(data); 
        break; 
       } 
      case "floor": 
       { 
        addBaseImg(data); 
        break; 
       } 
      default: 
       { 
        addOtherObjects(data); 
       } 
     } 
    }); 
}); 

這裏是一個加載圖像的情況下的一個例子:

最初的函數觸發click事件:

function addTexture(data) { 
    $('img[data-obj-id="' + data.object_id + '"]').trigger("click"); 
} 
導致此功能的

$(document).on("click", ".img-patt", function() { 

    var imgURL = $(this).data("src"); 

    var _this = this; 

    //this is where the process skips to the next iteration, before the image is loaded and added to the canvas 

    fabric.Image.fromURL(imgURL, function (img) { 

     //some code to handle the pattern removed from here just to shorten up the snippet 

     var rect = new fabric.Rect({ 
      name: "texture", 
      visible: true, 
      selectable: false, 
      data: { 
       type: $(_this).data("type"), 
       objid: $(_this).data("obj-id") 
      }, 
      top: 0, 
      left: 0, 
      width: fabCanvas.width, 
      height: fabCanvas.height, 
      fill: pattern 
     }); 

     fabCanvas.add(rect); 
     fabCanvas.renderAll(); 
    }); 

}); 
+1

你號無法進行循環等待。但你可以模仿一個循環延遲使用遞歸 – Rajesh

+0

我最近[回答](https://stackoverflow.com/a/43535024/3783478)類似的[問題](https://stackoverflow.com/questions/43534797/keep -for - 環 - 從執行的功能於的JavaScript/43535024#43535024)。你可以嘗試嵌入它 – Rajesh

+0

看看這個https://stackoverflow.com/questions/16149431/make-function-wait-until-element-exists請告訴它是否有幫助! 乾杯! –

回答

0

如果你想手動處理它而不是依賴某種Promise實現(例如藍鳥),你可以使用這個邏輯。

整體看起來比較複雜,但除了應該有效的事實之外,當你看到並認識到這一點時,添加應用知識,你就可以做更小,更好的事情。

這個概念不是在畫布上添加圖像,而是創建一個已經加載的對象的有序數組,然後當您全部加載它們時,在畫布上添加該數組對象。

你的onclick變爲:

function addToCanvas(object) { 
    canvas.add(object); 
} 

$(document).on("click", ".img-patt", function() { 

    var imgURL = $(this).data("src"); 

    addSomething(imgUrl, null, null, addToCanvas) 

}); 

你添加的東西是:

function addSomething(imgUrl, index, objectStack, callback) { 

     //this is where the process skips to the next iteration, before the image is loaded and added to the canvas 

     fabric.Image.fromURL(imgURL, function (img) { 

      //some code to handle the pattern removed from here just to shorten up the snippet 

      var rect = new fabric.Rect({ 
       name: "texture", 
       visible: true, 
       selectable: false, 
       data: { 
        type: $(_this).data("type"), 
        objid: $(_this).data("obj-id") 
       }, 
       top: 0, 
       left: 0, 
       width: fabCanvas.width, 
       height: fabCanvas.height, 
       fill: pattern 
      }); 

      objectStack && objectStack[index] = rect; 
      callback(rect) 
      }); 
} 

你的主循環變爲:(for循環和foreach都是sincronous)

$.ajax({ 
    url: url, 
    method: "GET" 
}).done(function (data) { 
    var objectStack = new Array(data.length); 
    var loaded = data.length; 
    var onFinish = function() { 
     loaded-- 
     if (loaded === 0) { 
     objectStack.forEach(function(object) { 
      canvas.add(object); 
     }); 
     } 
    } 
    data.forEach(function (data, index) { 
     var src = $('img[data-obj-id="' + data.object_id + '"]').data('src'); 
     switch (data.layer_type) { 
      case "texture": 
       { 
        addSomething(src, index, objectStack, onFinish) 
        break; 
       } 
      case "color": 
       { 
        ... 
       } 
      case "room": 
       { 
        ... 
       } 
      case "decor": 
       { 
        ... 
       } 
      case "floor": 
       { 
        ... 
       } 
      default: 
       { 
        ... 
       } 
     } 
    }); 
}); 
+0

我喜歡這個想法,現在就試試吧! –

+0

我實施了這種方法,它工作完美!非常感謝。我能夠使用相同的方法處理我的應用程序的另一部分,這些部分有類似的問題(由於從URL加載圖像而導致元素加載失敗),並修復了該問題。 –

-2

你可能想要使用一個技巧,你應該得到你想要的。

在開始之前設置一個強制等待的變量。

現在我告訴你,你的情況

var wait = false; 
$.ajax({ 
    url: url, 
    method: "GET" 
}).done(function (data) { 
    wait = true; 
    data.forEach(function (data) { 
     switch (data.layer_type) { 
      case "texture": 
       { 
        addTexture(data) 
        break; 
       } 
      ... 
      default: 
       { 
        addOtherObjects(data); 
       } 
     } 
    }); 
    wait=false; 
}); 

,並在click事件,你必須這樣做

$(document).on("click", ".img-patt", function() { 
    if (wait){ 
    // do samething 
    }else{ 

    } 
}); 

另外,如果你把一個定時器和一個功能變得更可靠

function DoSamething(){ 
    if (wait){ 
     // do samething 
    }else{ 
     window.setInterval(DoSamething, 1000); 
    } 
} 

您的點擊事件將如此

$(document).on("click", ".img-patt", function() { 
    window.setInterval(DoSamething, 1000); 
}); 
相關問題