Javascript 对象关键点映射-如何暂停迭代

Javascript 对象关键点映射-如何暂停迭代,javascript,html,dictionary,Javascript,Html,Dictionary,我正在制作一个简单的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 = ()

我正在制作一个简单的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()
迭代

在加载imgObj时是否可以暂停.map()迭代

不是。因此,您使用异步循环。以下是一个示例,请参见注释:

// 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);
然后:

如果您出于某种原因希望(在等待前一个图像时)暂停加载下一个图像,则可以使用该
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
异步
/
等待

// 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
没有意义,B)使用数组
map
返回。如果不这样做,只需使用
forEach
(或
for
for of
循环)

在加载imgObj时是否可以暂停.map()迭代

不是。因此,您使用异步循环。以下是一个示例,请参见注释:

// 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);
然后:

如果您出于某种原因希望(在等待前一个图像时)暂停加载下一个图像,则可以使用该
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
异步
/
等待

// 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
没有意义,B)使用数组
map
返回。如果不这样做,只需使用
forEach
(或
for
for of
循环)。

您不能这样做。不过,您可以使用递归来实现这一点,这是不可能的,因为在您返回到事件循环之前,JS不会触发事件,即使图像已加载。你必须以异步的方式重新设计你的代码。通过一些小的调整,这个问题中解决方案的ES6部分也会起作用:你不能。不过,您可以使用递归来实现这一点,这是不可能的,因为在您返回到事件循环之前,JS不会触发事件,即使图像已加载。您必须以异步方式重新设计代码。通过一些小的调整,这个问题中解决方案的ES6部分也会起作用:另一种方法是让浏览器一次加载所有图像,然后等待所有的
onload
事件发生。这样做的好处是,如果一个特定图像的加载速度比其他图像慢,它就不会阻止队列。@Haroldo_好的:这是一种更好的方法。我在解释OP的代码时非常直截了当,不是吗?啊@Andreas的评论更接近于我将如何实现它(使用
Promise.all()
):@Haroldo_OK:添加了并行选项和基于承诺的顺序选项(以防万一)。@Dominik
imgObj.src=img来自您的脚本。在评论的第二部分,您错过了
。它是
const-loadImage=src=>new-Promise(…)
,在本例中,它与:
function-loadImage(src){return-new-Promise(…);}
->相同,另一种方法是要求浏览器一次加载所有图像,然后等待所有
onload
事件发生。这样做的好处是,如果一个特定图像的加载速度比其他图像慢,它就不会阻止队列。@Haroldo_好的:这是一种更好的方法。我在解释OP的代码时非常直截了当,不是吗?啊@Andreas的评论更接近于我将如何实现它(使用
Promise.all()
):@Haroldo_OK:添加了并行选项和基于承诺的顺序选项(以防万一)。@Dominik
imgObj.src=img来自您的脚本。在评论的第二部分,您错过了
。它是
const loadImage=src=>newpromise(…)
,在本例中,它与:
function loadImage(src){returnnewpromise(…);}
->