javascript - 对象键映射 - 如何暂停迭代

标签 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 = () => {
            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 (或 forfor-of 循环)。

关于javascript - 对象键映射 - 如何暂停迭代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45936899/

相关文章:

javascript - 将外部 jQuery 文件包含在 $(document).ready() 中

javascript - d3 表超出 div 边界

html - 将具有 2 种不同字体大小的段落居中

Python - 扁平字典,其中一些键是 'missing'

ios - 如何在 Swift 中访问深层嵌套的对象

c++ - 如何初始化一个以priority_queue为值的map与priority_queue的比较对象?

javascript - 返回 tr 的引用

HTML 和 CSS 边距

javascript - 如何使用提交按钮在angularJS中提交表单的所有详细信息

javascript - JS ES6 类 ToString() 方法即使在 Babel 或 Chrome 中也不起作用