代码之家  ›  专栏  ›  技术社区  ›  leonheess

创建多个画布图案失败

  •  2
  • leonheess  · 技术社区  · 6 年前

    我正在尝试创建一个用于 Chart.js 圆环图,我这样做:

    var surfacePatterns;
    var surfaceNames = ['Unknown', 'Paved', 'Unpaved', 'Concrete', 'Cobblestone', 'Metal', 'Wood', 'Ground', 'Sand', 'Grass'];
    
    
    $(document).ready(() => {    
        surfacePatterns = [];
        console.log(surfacePatterns);
        for (i = 0; i < surfaceNames.length; i++) {
            var temp = new Image();
            temp.onload = () => surfacePatterns.push($("#canvas1")[0].getContext('2d').createPattern(temp, 'repeat'));
            temp.src = '../img/surfaces/'+ surfaceNames[i] + '.jpg';
        }
    });
    
    function chart(){
       console.log(surfacePatterns);
    }
    

    这个 chart() 按按钮调用函数。我故意等待几秒钟,这样它就可以加载图像并创建模式,但当我调用函数时,它给出了以下信息:

    console

    在九幅图像中,只有8幅和9幅被转换成了模式,其余的都是空的。我不知道发生了什么,因为我没有错误,所有的图像都被找到了。如果我在 surfaceNames 我,如预期的那样,得到一个错误,一个图像找不到,如果我使用模式8和9,它们工作得很好。

    另一件奇怪的事:如果我改变

    temp.onload = () => surfacePatterns.push($("#canvas1")[0].getContext('2d').createPattern(temp, 'repeat'));
    

    temp.onload = () => surfacePatterns[i] = canvas1[0].getContext('2d').createPattern(temp, 'repeat');
    

    整个数组完全为空(=/=null)。另外,将数组初始化为空数组后的第一个日志提供了一个长度为9的空数组,我不知道为什么,因为还没有发生其他事情。

    我对javascript的理解有限,所以我会感谢关于这一切发生原因的每一个提示。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Patrick Roberts Benjamin Gruenbaum    6 年前

    您需要等待所有模式加载,然后才能记录数组。实际上,数组应该是 结果 等待所有模式,而不是异步填充的外部作用域中的变量。见 Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

    至于如何解决这个问题,您可以使用 Promise.all() 将每个回调转换为挂起的承诺后:

    const surfaceNames = ['stackoverflow.com', 'codegolf.stackexchange.com', 'superuser.com', 'codereview.stackexchange.com'];
    const context = document.querySelector('#canvas1').getContext('2d');
    const promises = surfaceNames.map(surfaceName =>
      new Promise((resolve, reject) => {
        const image = new Image();
    
        image.addEventListener('load', () => {
          resolve(context.createPattern(image, 'repeat'));
        });
        image.addEventListener('error', () => {
          reject(new Error(`${surfaceName} failed to load ${image.src}`));
        });
        image.src = `https://${surfaceName}/favicon.ico`;
      }).catch(error => {
        // populating array with null entry and logging error
        // instead of ignoring all the other pending promises
        console.log(error.message);
        return null;
      })
    );
    
    Promise.all(promises).then(surfacePatterns => {
      console.log(surfacePatterns.map(pattern => pattern.constructor.name));
    });
    <canvas id="canvas1"></canvas>

    如您所见,每一个都成功地通过 CanvasPattern .

        2
  •  1
  •   Kolzar    6 年前

    在“for”中多次调用异步函数时,必须等待所有调用。如果不等待,则会丢失一些异步调用,并得到一个空数组。

    如果你能剪断,我会设法解决这个问题。

    window.surfacePatterns = [];
    window.c = 0;
    //window.surfaceNames = ['Unknown', 'Paved', 'Unpaved', 'Concrete', 'Cobblestone', 'Metal', 'Wood', 'Ground', 'Sand', 'Grass'];
    window.surfaceNames = ["https://www.worldatlas.com/r/w1200-h630-c1200x630/upload/37/99/85/northern-pygmy-owl.jpg",
    "https://www.friendsofwehr.org/wp-content/uploads/2013/06/Great-horned_Owl_RWD_at_CRC1transparent.jpg"];
    
    $(document).ready(() => {  
        console.log('Step 1: ',window.surfacePatterns);
        for (i = 0; i < window.surfaceNames.length; i++) {
            var temp = new Image();
            temp.onload = function(){ 
    	        var my = $(".canvas1")[0].getContext('2d').createPattern(temp, 'repeat');
        	    console.log('Step inside async: ',my);
            	window.surfacePatterns.push(my);
              window.c++;
              if (window.surfaceNames.length === c) {
                console.log('Complete async calls: ',window.surfacePatterns);
              }
            }
            //temp.src = '../img/surfaces/'+ window.surfaceNames[i] + '.jpg';
            temp.src = "https://www.friendsofwehr.org/wp-content/uploads/2013/06/Great-horned_Owl_RWD_at_CRC1transparent.jpg"
    
        }
        console.log('Outside For: ', window.surfacePatterns);
    });
    
    function chart(){
    	console.log(window.surfacePatterns);
    }
    <!DOCTYPE html>
    <html>
    <body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <canvas class="canvas1"></canvas>
    <canvas class="canvas1"></canvas>
    
    </body>
    </html>

    最好告诉我。