我正在制作一个简单的 html5 游戏。
Object.keys(gameConfig.playerElems).map((e) =>{
let img = gameConfig.playerElems[e];
let name = e;
let imgObj;
imgObj = new Image();
imgObj.src = img;
imgObj.onload = () => {
playerElemsCounter++;
drawPlayer(imgObj);
}
});
加载 imgObj
时是否可以暂停 .map()
迭代?
最佳答案
Is it possible to pause .map() iteration while imgObj will be loaded?
没有。因此,您可以使用异步循环。这是一个例子,请参阅评论:
// A named IIFE
(function iteration(keys, index) {
// Get info for this iteration
let name = keys[index];
let img = gameConfig.playerElems[name];
let imgObj = new Image();
// Set event callbacks BEFORE setting src
imgObj.onload = () => {
playerElemsCounter++;
drawPlayer(imgObj);
next();
};
imgObj.onerror = next;
// Now set src
imgObj.src = img;
// Handles triggering the next iteration on load or error
function next() {
++index;
if (index < keys.length) {
iteration(keys, index);
}
}
})(Object.keys(gameConfig.playerElems), 0);
但是,正如 Haroldo_OK 指出的那样,这将等待一张图像加载后再请求下一张图像,这不仅是不必要的,而且是有害的。相反,请求所有这些,在收到它们时绘制它们,然后继续。您可以通过给自己一个返回 promise 的加载函数来做到这一点:
const loadImage = src => new Promise((resolve, reject) => {
const imgObj = new Image();
// Set event callbacks BEFORE setting src
imgObj.onload = () => { resolve(imgObj); };
imgObj.onerror = reject;
// Now set src
imgObj.src = src;
});
然后:
// Load in parallel, draw as we receive them
Promise.all(Object.keys(gameConfig.playerElems).map(
key => loadImage(gameConfig.playerElems[key])
.then(drawPlayer)
.catch(() => drawPlayer(/*...placeholder image URL...*/))
)
.then(() => {
// All done, if you want to do something here
});
// No need for `.catch`, we handled errors inline
如果您想要(出于某种原因)在等待上一张图像时暂停加载下一张图像,则可以使用不同的方式使用 loadImage
函数来执行此操作,例如具有经典 Promise reduce
模式的实例:
// Sequential (probably not a good idea)
Object.keys(gameConfig.playerElems).reduce(
(p, key) => p.then(() =>
loadImage(gameConfig.playerElems[key])
.then(drawPlayer)
.catch(() => drawPlayer(/*...placeholder image URL...*/))
)
,
Promise.resolve()
)
.then(() => {
// All done, if you want to do something here
});
// No need for `.catch`, we handled errors inline
...或使用 ES2017 async
/await
:
// Sequential (probably not a good idea)
(async function() {
for (const key of Object.keys(gameConfig.playerElems)) {
try {
const imgObj = await loadImage(gameConfig.playerElems[name]);
playerElemsCounter++;
drawPlayer(imgObj);
} catch (err) {
// use placeholder
drawPlayer(/*...placeholder image URL...*/);
}
}
})().then(() => {
// All done
});
// No need for `.catch`, we handled errors inline
<小时/>
旁注:如果您不是 A) 从回调中返回一个值以用于填充 map
创建的新数组,则使用 map
是没有意义的,并且B) 使用数组 map
返回。如果您不这样做,只需使用 forEach
(或 for
或 for-of
循环)。
关于javascript - 对象键映射 - 如何暂停迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45936899/