createImageBitmap 仅在页面重新加载后执行

Posted

技术标签:

【中文标题】createImageBitmap 仅在页面重新加载后执行【英文标题】:createImageBitmap only executing after page is reloaded 【发布时间】:2021-11-28 02:08:25 【问题描述】:

当我加载我的网页时,createImageBitmap 行没有运行并且我的承诺列表为空,但是当我重新加载页面时,承诺在列表中,并且列表似乎在函数被调用。这会导致问题并使我的游戏崩溃,因为没有将承诺解析为图像。

为什么会发生这种情况,我可以做些什么来解决它?

这是修改后的代码摘录:

Spritesheets = 
    tileset_grass : new Image(),
    tileset : new Image(),
    player : new Image(),
    crawler : new Image(),
    creature : new Image(),
    items : new Image(),
    particles : new Image()
;
Spritesheets.tileset_grass.src = "images/tileset_grass.png";
Spritesheets.tileset.src = "images/tileset.png";
Spritesheets.player.src = "images/player.png";
Spritesheets.crawler.src = "images/crawler.png";
Spritesheets.creature.src = "images/creature.png";
Spritesheets.items.src = "images/items.png";
Spritesheets.particles.src = "images/particles.png";

// separates spritesheets into separate sprites
Images = 
    tileset_grass : 
        spriteW : 16,
        spriteH : 18
    ,
    tileset : 
        spriteW : 16,
        spriteH : 16
    ,
    player : 
        spriteW : 16,
        spriteH : 16
    ,
    crawler : 
        spriteW : 16,
        spriteH : 16
    ,
    creature : 
        spriteW : 16,
        spriteH : 16
    ,
    items : 
        spriteW : 16,
        spriteH : 16
    ,
    particles : 
        spriteW : 16,
        spriteH : 16
    ,
;

console.log(Images)

function loadSprites() 
    for(let i = 0; i < Object.keys(Images).length; i++) 
        for(let k = 0; k < Spritesheets[Object.keys(Images)[i]].naturalWidth / Images[Object.keys(Images)[i]].spriteW; k++) 
            Images[Object.keys(Images)[i]][k] = createImageBitmap(Spritesheets[Object.keys(Images)[i]], k * Images[Object.keys(Images)[i]].spriteW, 0, Images[Object.keys(Images)[i]].spriteW, Images[Object.keys(Images)[i]].spriteH);
        ;
    ;
    console.log(Images)
;

loadSprites();

【问题讨论】:

【参考方案1】:

当将 htmlImageElement 作为createImageBitmap() 的源传递时,该元素必须处于解码状态,即其load 事件必须已触发。

当您重新加载页面时它会起作用,因为您很幸运,并且图像从缓存中加载得足够快。

因此,您可以在调用所有 createImageBitmap() 之前等待所有这些 HTMLImageElements 的 load 事件,或者您可以通过将所有资源作为 Blob 获取并创建 ImageBitmap 来重构代码以使其更快*直接来自这些 Blob,但是您需要将图像的大小以及裁剪选项存储在 JS 中。

Spritesheets = 
  tileset_grass : "images/tileset_grass.png",
  tileset : "images/tileset.png",
  player : "images/player.png",
  crawler : "images/crawler.png",
  creature : "images/creature.png",
  items : "images/items.png",
  particles : "images/particles.png"
;

// separates spritesheets into separate sprites
Images = 
  tileset_grass : 
    // add the image's width and height info here (or somewhere else)
    width: XXX,
    height: XXX,
    spriteW : 16,
    spriteH : 18
  
;

async function loadSprites() 
  const keys = Object.keys(Images);
  for(let i = 0; i < keys.length; i++) 
    const key = keys[i];
    // fetch as Blob
    const blob = await fetch(Spritesheets[key]).then(resp => resp.ok && resp.blob());
    const img = Images[key];

    for(let k = 0; k < img.width / img.spriteW; k++) 
      img[k] = await createImageBitmap(blob, k * img.spriteW, 0, img.spriteW, img.spriteH);
    ;
  ;
  console.log(Images)
;
它不一定会像花更少的挂钟时间来执行那样“更快”,但它可以让浏览器做更少的工作并同时优化其他任务。

【讨论】:

以上是关于createImageBitmap 仅在页面重新加载后执行的主要内容,如果未能解决你的问题,请参考以下文章

如何仅在 Angular 的某些页面上显示标题组件(现在它仅在重新加载时显示)

仅在 html 代码中使用 javascript 重新加载特定页面一次

背景图像仅在重新加载页面后显示

内容仅在重新加载后显示

成功的PHP登录仅在重新加载页面后出现

Jquery Mobile:“pageshow”事件仅在 Shift F5(完全重新加载)时触发,但在加载另一个页面或具有不同查询的同一页面时不会触发