ImageLoader benchmark

JavaScript performance comparison

Revision 3 of this test case created by Ryan Lester

Preparation code

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

      
<script>
Benchmark.prototype.setup = function() {
  // assume JQuery is loaded under $
  // options: { src, callback, timeout }
  var ImageJob = function (options) {
      $.extend(true, this, {
          jobId: null,
      }, options);
      /**
       * Image object which will contain downloaded image.
       * @member {Image} image
       * @memberof OpenSeadragon.ImageJob#
       */
      this.image = null;
  };
  ImageJob.prototype = {
      /**
       * Initiates downloading of associated image.
       * @method
       */
      start: function () {
          var _this = this;
          this.image = new Image();
          this.image.onload = function () {
              _this.finish(true);
          };
          this.image.onabort = this.image.onerror = function () {
              _this.finish(false);
          };
          this.jobId = window.setTimeout(function () {
              _this.finish(false);
          }, this.timeout);
          this.image.src = this.src;
      },
      finish: function (successful) {
          this.image.onload = this.image.onerror = this.image.onabort = null;
          if (!successful) this.image = null;
          if (this.jobId) {
              window.clearTimeout(this.jobId);
          }
          this.callback(this, successful);
      }
  };
  /**
   * @class
   * @classdesc Handles downloading of a set of images using asynchronous queue pattern.
   */
  var ImageLoader = function (jobLimit) {
      $.extend(true, this, {
          jobLimit: jobLimit,
          jobQueue: [
          ],
          jobsInProgress: 0
      });
  };
  ImageLoader.prototype = {
      /**
       * Add an unloaded image to the loader queue.
       * @method
       * @param {String} source - URL of image to download.
       * @param {Function} callback - Called once image has been downloaded.
       */
      addJob: function (options) {
          var _this = this,
          complete = function (job, successful) {
              completeJob(_this, job, successful, options.callback);
          },
          jobOptions = {
              src: options.src,
              callback: complete,
              timeout: 5000
          },
          newJob;
          newJob = new ImageJob(jobOptions);
          if (this.jobsInProgress < this.jobLimit) {
              newJob.start();
              this.jobsInProgress++;
          } 
          else {
              this.jobQueue.push(newJob);
          }
      }
  };
  /**
   * Cleans up ImageJob once completed.
   * @method
   * @private
   * @param loader - ImageLoader used to start job.
   * @param job - The ImageJob that has completed.
   * @param callback - Called once cleanup is finished.
   */
  function completeJob(loader, job, successful, callback) {
      var nextJob;
      loader.jobsInProgress--;
      if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) {
          nextJob = loader.jobQueue.shift();
          nextJob.start();
      }
      callback(job.src, successful);
  }
  function naiveLoader(src, callback) {
      var jobId,
          image = new Image();
  
      image.onload = function () {
          window.clearTimeout(jobId);
          callback(src, true);
      };
      image.onabort = image.onerror = function () {
          window.clearTimeout(jobId);
          callback(src, false);
      };
      jobId = window.setTimeout(function () {
          callback(src, false);
      }, 5000);
  
      image.src = src;
  }
  
  // Collection of images to download
  var testImages = [];
  (function (testImages) {
      var rootUrl = 'https://openseadragon.github.io/example-images/highsmith/highsmith_files/12/',
      total = 100,
      firstDigit = 0,
      lastDigit = 0,
      extension = '.jpg',
      i = 0,
      nextName = null;
      for (i = 0; i < total; i++) {
          nextName = rootUrl + firstDigit + '_' + lastDigit + extension;
          testImages.push(nextName);
          // roll to next name
          lastDigit = (lastDigit + 1) % 10;
          firstDigit = (lastDigit === 0) ? firstDigit + 1 : firstDigit;
      }
  }(testImages));
  
  // test cases for image loader
  function benchmarkLoader(jobLimit) {
      var imageLoader = new ImageLoader(jobLimit),
      imagesRemaining = testImages.length,
      loadingDispatch = function (src) {
          imageLoader.addJob({
              src: src,
              callback: callback
          });
      },
      callback = function (src, successful) {
          if (successful && imagesRemaining > 0) {
              imagesRemaining--;
          } 
          else if (successful && imagesRemaining === 0) {
              deferred.complete();
              // or w/e the completion op is
          } 
          else {
              // restart download
              window.setTimeout(function () {
                  loadingDispatch(src);
              }, 1);
          }
      };
      for (var imageSrc in testImages) {
          loadingDispatch(imageSrc);
      }
  }
  function benchmarkNaive() {
      var imagesRemaining = testImages.length,
      loadingDispatch = function (src) {
          naiveLoader(src, callback);
      },
      callback = function (src, successful) {
          if (successful && imagesRemaining > 0) {
              imagesRemaining--;
          } 
          else if (successful && imagesRemaining <= 0) {
              deferred.complete();
              // or w/e the completion op is
          } 
          else {
              // restart download
              window.setTimeout(function () {
                  loadingDispatch(src);
              }, 1);
          }
      };
      for (var imageSrc in testImages) {
          loadingDispatch(imageSrc);
      }
  }

};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
ImageLoader1
// async test
benchmarkLoader(1);
pending…
ImageLoader2
// async test
benchmarkLoader(2);
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL.

0 Comments