function createTextures(gl, textureOptions, callback) {
    callback = callback || noop;
    var numDownloading = 0;
    var errors = [];
    var textures = {};
    var images = {};

    function callCallbackIfReady() {
      if (numDownloading === 0) {
        setTimeout(function() {
          callback(errors.length ? errors : undefined, textures, images);
        }, 0);
      }
    }

    Object.keys(textureOptions).forEach(function(name) {
      var options = textureOptions[name];
      var onLoadFn;
      if (isAsyncSrc(options.src)) {
        onLoadFn = function(err, tex, img) {
          images[name] = img;
          --numDownloading;
          if (err) {
            errors.push(err);
          }
          callCallbackIfReady();
        };
        ++numDownloading;
      }
      textures[name] = createTexture(gl, options, onLoadFn);
    });

    // queue the callback if there are no images to download.
    // We do this because if your code is structured to wait for
    // images to download but then you comment out all the async
    // images your code would break.
    callCallbackIfReady();

    return textures;
  }
Creates a bunch of textures based on the passed in options.

Example:

    var textures = twgl.createTextures(gl, {
      // a power of 2 image
      hftIcon: { src: "images/hft-icon-16.png", mag: gl.NEAREST },
      // a non-power of 2 image
      clover: { src: "images/clover.jpg" },
      // From a canvas
      fromCanvas: { src: ctx.canvas },
      // A cubemap from 6 images
      yokohama: {
        target: gl.TEXTURE_CUBE_MAP,
        src: [
          'images/yokohama/posx.jpg',
          'images/yokohama/negx.jpg',
          'images/yokohama/posy.jpg',
          'images/yokohama/negy.jpg',
          'images/yokohama/posz.jpg',
          'images/yokohama/negz.jpg',
        ],
      },
      // A cubemap from 1 image (can be 1x6, 2x3, 3x2, 6x1)
      goldengate: {
        target: gl.TEXTURE_CUBE_MAP,
        src: 'images/goldengate.jpg',
      },
      // A 2x2 pixel texture from a JavaScript array
      checker: {
        mag: gl.NEAREST,
        min: gl.LINEAR,
        src: [
          255,255,255,255,
          192,192,192,255,
          192,192,192,255,
          255,255,255,255,
        ],
      },
      // a 1x2 pixel texture from a typed array.
      stripe: {
        mag: gl.NEAREST,
        min: gl.LINEAR,
        format: gl.LUMINANCE,
        src: new Uint8Array([
          255,
          128,
          255,
          128,
          255,
          128,
          255,
          128,
        ]),
        width: 1,
      },
    });

Now

*   `textures.hftIcon` will be a 2d texture
*   `textures.clover` will be a 2d texture
*   `textures.fromCanvas` will be a 2d texture
*   `textures.yohohama` will be a cubemap texture
*   `textures.goldengate` will be a cubemap texture
*   `textures.checker` will be a 2d texture
*   `textures.stripe` will be a 2d texture

@param {WebGLRenderingContext} gl the WebGLRenderingContext
@param {Object.<string,module:twgl.TextureOptions>} options A object of TextureOptions one per texture.
@param {module:twgl.TexturesReadyCallback} [callback] A callback called when all textures have been downloaded.
@return {Object.<string,WebGLTexture>} the created textures by name
@memberOf module:twgl/textures