4
\$\begingroup\$

I use the src.sencha.io service to resize images on the fly according to device width, saving lots of bandwidth on mobiles etc.

Sometimes the service fails randomly with a 503 error, so a fallback is needed. I've written this JS to fallback to "non-sencha" urls, and emit an error event, if the first image requested through sencha fails.

This is my first open-sourced bit of code, so am keen to get feedback on my:

  • code correctness
  • whether this prototype-based design pattern is appropriate
  • alternative better patterns
  • comment/code clarity

Even just confirming whether it's good would be helpful, as I don't have any formal programming training to be confident.

Github repo here.

jsfiddle with test case prepared for you here.

/** SENCHA SRC IMAGE FALLBACK ***************************************
 *
 * Author: Josh Harrison (http://www.joshharrison.net/)
 * URL: https://github.com/ultrapasty/sencha-src-image-fallback
 * Version: 1.0.0
 * Requires: jQuery
 *
 * Tests to see if the src.sencha.io service is down, and if so,
 * falls back to local images, by removing the sencha domain
 * from the src.
 *
 * Can be instantiated with `new SenchaSRCFallback().init();`
 * Or `var instance = new SenchaSRCFallback().init();`
 *
 * Emits the event `senchafailure` if sencha fails.
 * Listen with `instance.onsenchafailure = func;`
 *
 */

;(function(window, $) {

  var SenchaSRCFallback = function() {

    this.sencha_path_identifier = '.sencha.io/';
    this.sencha_path_regex = /http:\/\/src[1-4]?\.sencha\.io\//i;
    this.$imgs = null;

  };
  SenchaSRCFallback.prototype = {

    init : function() {
      this.$imgs = $("img[src*='" + this.sencha_path_identifier + "']");

      if(this.$imgs.length) {
        this.test_sencha_availability();
      }

      return this;
    },

    test_sencha_availability : function() {
      var t = this, img = new Image();

      img.onerror = function() {
        $(t).trigger("senchafailure");
        t.fallback_to_local_srcs();
      };

      img.src = this.$imgs[0].getAttribute("src");
    },

    fallback_to_local_srcs : function() {
      var t = this;

      this.$imgs.each(function() {
        this.setAttribute("src", this.getAttribute("src").replace(t.sencha_path_regex, ""));
      });
    }

  };

  window.SenchaSRCFallback = SenchaSRCFallback;

})(window, jQuery);

// Example usage:

// Instantiate the fallback
var senchafallback = new SenchaSRCFallback().init();

// Listen for failure like this:
senchafallback.onsenchafailure = function() {
    console.log("It failed.");
    // log failure event in google analytics, etc
};

Images would be initially routed through src.sencha.io to avoid downloading twice. With the above JS, should sencha fail, these image tags:

<img src="http://src.sencha.io/http://mysite.com/image1.png">
<img src="http://src1.sencha.io/http://mysite.com/image2.png">
<img src="http://src2.sencha.io/http://mysite.com/image3.png">

... would become the following:

<img src="http://mysite.com/image1.png">
<img src="http://mysite.com/image2.png">
<img src="http://mysite.com/image3.png">
\$\endgroup\$
2
\$\begingroup\$

I like the idea, from a once over:

  • Since you use an IIFE I would declare sencha_path_identifier and sencha_path_regex outside of the constructor, then you can access them without specifying this.
  • I would do either function SenchaSRCFallback() { or var SenchaSRCFallback = function SenchaSRCFallback() {, anonymous functions are a pain to troubleshoot
  • Why do you require the caller to call init()? In my mind this call should be done within the constructor.

This is something I might borrow at some point.

\$\endgroup\$
2
  • \$\begingroup\$ One thought on your first point – is it better to store this on the object, in order to avoid one extra look up the chain? Also on the third point, I may want to use var instance = new SenchaImageFallback(); instance.onsenchafailure = func; instance.init() to bind the fail fallback before it attempts to request the image. Is this a good reason to require the call to init() separately? \$\endgroup\$ – Josh Harrison Mar 6 '14 at 10:05
  • 1
    \$\begingroup\$ 1. I think it makes for cleaner code, performance penalty should be minimal if any. 2. I would actually make func an optional parameter of the constructor in that case. \$\endgroup\$ – konijn Mar 6 '14 at 11:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.