Read more

JavaScript: Polyfill native Promise API with jQuery Deferreds

Henning Koch
August 05, 2017Software engineer at makandra GmbH

Native Promise is supported by all current browsers.

You should prefer native promises Show archive.org snapshot to jQuery's Deferreds Show archive.org snapshot . Native promises are much faster than their jQuery equivalent.

Illustration book lover

Growing Rails Applications in Practice

Check out our e-book. Learn to structure large Ruby on Rails codebases with the tools you already know and love.

  • Introduce design conventions for controllers and user-facing models
  • Create a system for growth
  • Build applications to last
Read more Show archive.org snapshot

Native promises are supported on all browsers except IE <=11, Android <= 4.4 and iOS <= 7 Show archive.org snapshot .

If you need Promise support for these old browsers you can use a Polyfill. A very fast and small (2 KB minified and gzipped) polyfill is Zousan Show archive.org snapshot .

If you want to waste even fewer bytes, you can use jQuery's deferreds to polyfill the native Promise API. The result is extremely small (339 bytes minfied and gzipped), but has the same performance limitations of jQuery deferreds. Obviously this makes only sense in a project that is using jQuery anyway.

Below is the polyfill in Coffeescript Show archive.org snapshot . It is mostly compliant with Promises A+ spec if you are using jQuery 3+:

window['Promise'] ||= class

  constructor: (executor) ->
    @deferred = $.Deferred()
    executor(@deferred.resolve, @deferred.reject)

  then: (fulfilled, rejected) =>
    @deferred.then(fulfilled, rejected)

  catch: (rejected) =>
    @then(undefined, rejected)

  @race: (promises) ->
    settled = false
    winner = $.Deferred()

    settle = (settler, value) ->
      unless settled
        settled = true
        winner[settler](value)
      undefined

    fulfilled = settle.apply(this, 'resolve')
    rejected = settle.apply(this, 'reject')

    for promise in promises
      promise.then(fulfilled, rejected)

    winner.promise()

  @all: (promises) ->
    # Pass an additional resolved deferred to $.when so $.when will
    # not return the given deferred if only one deferred is passed.
    $.when(@resolve(), promises...)

  @reject: (value) ->
    deferred = $.Deferred()
    deferred.reject(value)
    deferred.promise()

  @resolve: (value) ->
    deferred = $.Deferred()
    deferred.resolve(value)
    deferred.promise()
Posted by Henning Koch to makandra dev (2017-08-05 16:33)