handleImageCompleted_(div, tileId, e, profileId) {
    if (e.type == goog.net.EventType.ERROR) {
      // Forward error events.
      goog.array.remove(this.tilesLoading, tileId);
      this.tilesFailed.add(tileId);
      this.dispatchEvent(e);
    } else {
      // Convert tile loading events to our own type.
      goog.array.remove(this.tilesLoading, tileId);
      var tile;
      if (e.target && (e.type == goog.events.EventType.LOAD)) {
        tile = /** @type {Node} */ (e.target);
        this.tiles_.add(tile);
        if (this.opacity_ != 1.0) {
          goog.style.setOpacity(/** @type {Element} */ (tile), this.opacity_);
        }
        div.appendChild(tile);
      }
      this.dispatchTileEvent_();
    }

    if (this.profiler_ && profileId !== null) {
      this.profiler_.addTile(tileId, profileId);
    }
  }
Handle image 'load' and 'error' events. When the last one has
finished, dispatch an ee.AbstractOverlay.EventType.TILE_LOADED event.
Handle bookkeeping to keep the tilesLoading array accurate.
@param {Node} div Tile div to which images should be appended.
@param {string} tileId The id of the tile that was requested.
@param {!goog.events.Event} e Image loading event.
@param {?string} profileId If profiling, profile ID for the tile.
@private