HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Detecting gyroscope data using promises

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
gyroscopepromisesusingdatadetecting

Problem

In a plugin that I am currently authoring, I am using a function to check whether the device provides gyroscopic data. Although intuitively this can be easily resolved by checking the value of window.DeviceOrientationEvent, i.e.:

if (window.DeviceOrientationEvent) {
    // Ok, device orientation event listening is supported!
}


…this statement also resolves true when on a device with no functional gyroscope, i.e. Google Chrome on a laptop. The event data returned for alpha, beta and gamma are, however, null. Basically, the window.DeviceOrientationEvent does not tell me if there is gyroscopic data available, but only informs me if the browser/user-agent supports the event.

Therefore, not only do I have to check for support for the event, but also have to cross verify the value of alpha, beta or gamma such that they are not null. The best way I could check is using promises, which I feel a bit cumbersome and long-winded:

var check = {
    // Does it have a working gyroscope?
    gyroscope: function() {
        var d = new $.Deferred(),
            handler = function(e) {
                d.resolve({
                    alpha: e.alpha,
                    beta: e.beta,
                    gamma: e.gamma
                });
                // Listen to device orientation once and remove listener immediately
                window.removeEventListener('deviceorientation', handler, false);
            };
        window.addEventListener('deviceorientation', handler, false);
        return d;
    }
}

// Wait for gyroscope data
$.when(check.gyroscope()).done(function(r) {
    if(r.alpha === null && r.beta === null && r.gamma === null) {
        console.log('Device has no functional gyroscope.');
    } else {
        console.log('Device has functional gyroscope.')
    }
});


I am wondering if there is a cleaner way to write this code?

Solution

-
I imagine you're still checking window.DeviceOrientationEvent? Because if that doesn't exist, you can presumably skip everything else.

-
When using $.Deferred you should always return its .promise() - not the deferred object itself. The deferred object itself is "read/write" (i.e. you can call resolve and reject on it), while the promise it creates is "read-only" which is what you want to pass on to other code.

-
You don't need $.when unless you're waiting for several promises to resolve. You can simple call promise.done() (or .then or .fail or .always)

-
Since the idea is get a yes/no answer, I'd simply use the resolve/reject callbacks of the deferred and do all the checking in one place.

-
I don't know if it's relevant, but checking strictly against null will give you a false positive if alpha etc.are actually completely undefined. It might be better to check typeof alpha === 'number'.

-
Of course, you don't really need promises; a simple callback would do.

For instance:

var check = {
  gyroscope: function (callback) {
    function handler(event) {
      var hasGyro = typeof event.alpha === 'number'
                 && typeof event.beta  === 'number'
                 && typeof event.gamma === 'number';
      window.removeEventListener('deviceorientation', handler, false);
      callback(hasGyro);
    }
    window.addEventListener('deviceorientation', handler, false);
  }
};

check.gyroscope(function (hasGyroscope) {
  if(hasGyroscope) {
    console.log('Device has functional gyroscope.')
  } else {
    console.log('Device has no functional gyroscope.');
  }
});


If you do want to use $.Deferred, I'd recommend something like:

var check = {
  gyroscope: function () {
    var deferred = $.Deferred();

    function handler(event) {
      var hasGyro = typeof event.alpha === 'number'
                 && typeof event.beta  === 'number'
                 && typeof event.gamma === 'number';
      window.removeEventListener('deviceorientation', handler, false);
      hasGyro ? deferred.resolve() : deferred.reject();
    }

    window.addEventListener('deviceorientation', handler, false);
    return deferred.promise();
  }
};

check.gyroscope().then(function () {
  console.log('Device has functional gyroscope.')
}, function () {
  console.log('Device has no functional gyroscope.');
});

Code Snippets

var check = {
  gyroscope: function (callback) {
    function handler(event) {
      var hasGyro = typeof event.alpha === 'number'
                 && typeof event.beta  === 'number'
                 && typeof event.gamma === 'number';
      window.removeEventListener('deviceorientation', handler, false);
      callback(hasGyro);
    }
    window.addEventListener('deviceorientation', handler, false);
  }
};

check.gyroscope(function (hasGyroscope) {
  if(hasGyroscope) {
    console.log('Device has functional gyroscope.')
  } else {
    console.log('Device has no functional gyroscope.');
  }
});
var check = {
  gyroscope: function () {
    var deferred = $.Deferred();

    function handler(event) {
      var hasGyro = typeof event.alpha === 'number'
                 && typeof event.beta  === 'number'
                 && typeof event.gamma === 'number';
      window.removeEventListener('deviceorientation', handler, false);
      hasGyro ? deferred.resolve() : deferred.reject();
    }

    window.addEventListener('deviceorientation', handler, false);
    return deferred.promise();
  }
};

check.gyroscope().then(function () {
  console.log('Device has functional gyroscope.')
}, function () {
  console.log('Device has no functional gyroscope.');
});

Context

StackExchange Code Review Q#90202, answer score: 3

Revisions (0)

No revisions yet.