我正在尝试创建一组用于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()
函数。我故意等待几秒钟,以便它可以加载图像并创建图案,但是当我调用该函数时,它会显示以下信息:
在9张图像中,只有8张和9张被转换为图案,其余为空。我不知道发生了什么,因为我没有错误并且找到了所有图像。如果我按预期在surfaceNames
中更改了一个String,则会收到一个错误消息,即找不到图像,并且如果我使用模式8和9,它们可以很好地工作。
另一个奇怪的事情:如果我改变
temp.onload = () => surfacePatterns.push($("#canvas1")[0].getContext('2d').createPattern(temp, 'repeat'));
到
temp.onload = () => surfacePatterns[i] = canvas1[0].getContext('2d').createPattern(temp, 'repeat');
整个数组完全为空(= / =空)。同样,将数组初始化为空数组后的第一个日志为我提供了一个长度为9的空数组,我不知道为什么,因为什么都没有发生。
答案 0 :(得分:1)
在这种情况下,如果在“ 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>
最好告诉我
答案 1 :(得分:1)
您需要等待所有模式加载后才能记录阵列。实际上,数组应该是等待所有模式的结果,而不是异步填充的外部作用域中的变量。参见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
解析。