Почему не выполняется сборка объекта изображения js? - PullRequest
0 голосов
/ 04 июля 2019

Я работаю на C ++ и изучаю javascript. Уроки Mozilla по webgl имеют код, подобный приведенному ниже (реальный код и ссылка внизу). Я пытаюсь понять, почему код в функции обратного вызова «onload» всегда будет выполняться. Мне кажется, что экземпляр объекта Image должен быть мусором в коде ниже. Таким образом, теоретически он может быть собран мусором до завершения загрузки и вызывает обратный вызов onload.

function foo()
{
  image = new Image();

  image.onload = function()
  {
     /*stuff to do when image gets done loading */
    Console.log(image.width);
  }

  image.src = url;
}

Единственная идея, которая у меня есть, заключается в том, что функция, использующая «image.width» - объект функции должен хранить экземпляр изображения в памяти. Но это будет ссылка на круг, потому что эта функция существует только на самом объекте изображения; Единственная ссылка на объект функции AFAIK - это свойство обратного вызова onload. Поэтому круговая ссылка (image-> onload-> function-> image-> ...) должна быть собрана мусором.

Кажется, я чего-то не понимаю, или между загрузкой изображения и его сборкой мусора возникает гонка.

JS Ссылка, показывающая круговые эталонные острова, которые более недоступны, должна собираться мусором. https://javascript.info/garbage-collection

Учебное пособие Ссылка: https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL

function loadTexture(gl, url) {
  const texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);

  // Put a single pixel in the texture until it loads
  const level = 0;  const internalFormat = gl.RGBA;  const width = 1;  const height = 1;  const border = 0;  const srcFormat = gl.RGBA;  const srcType = gl.UNSIGNED_BYTE;  const pixel = new Uint8Array([0, 0, 255, 255]);  // opaque blue
  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,width, height, border, srcFormat, srcType, pixel);

  const image = new Image();

  image.onload = function() {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,srcFormat, srcType, image);

    // WebGL1 has different requirements for power of 2 images vs non power of 2 images so check if the image is a power of 2 in both dimensions.
    if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
       gl.generateMipmap(gl.TEXTURE_2D); // Yes, it's a power of 2. Generate mips.
    } else {
       // No, it's not a power of 2. Turn off mips and set wrapping to clamp to edge
       gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
       gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
       gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    }
  };
  image.src = url;

  return texture;
}

//irrelevant, but including for completeness
function isPowerOf2(value)
{
    return (value & (value - 1)) == 0
}

1 Ответ

1 голос
/ 04 июля 2019

Когда вы назначаете image.src, объект Image добавляется во внутреннюю очередь браузера для всех внешних объектов, которые загружаются асинхронно.Эта очередь предотвращает превращение объекта в мусор сразу после возврата из функции.Очередь необходима только для того, чтобы браузер управлял процессом загрузки этих объектов - он должен сохранять загружаемые объекты, поэтому он знает, что делать, когда получает ответ от сервера.

Когдаизображение загружено, его функция onload добавлена ​​в очередь событий, и поскольку она имеет ссылку на объект через переменную image (а также контекст this функции и аргумент Event дляфункция), которая поддерживает живой объект во время работы функции.

Как только функция onload вернется, изображение станет мусором (поскольку нигде не сохраняет значение image).

...