Promise in Js

With Ken and Barbie

Created by Fabien Garcia

What is a promise?

a declaration that something will or will not be done, given, etc., by one

dictionary.com

The story of ken and barbie

Let's take Ken and Barbie:

ken = new PerfectMan()
barbie = new PerfectWoman()

They met and ken propose to barbie

So this is the classic process

ken.marry(barbie)

But what happen for real?

ken.marry(barbie)
  .then => ken.find(job)
  .then => child = Sex(ken, barbie)
  .then (child) => ken.takeCare(child); barbie.takeCare(child)
  .then => ken.die()
  .then => barbie.die()

The story of normal people

Have you met Ted?

ted = new Man()
robin = new Woman()

Ted want to marry but Robin not really ...

What happen when they met?

ted.marry(robin)
  .then => ted.find("job")
  .fail => robin = ted.find("otherWoman")
  .then => child = Sex(ken, robin)
  .then (child) => ken.takeCare(child); robin.takeCare(child)
  .then => ken.die()
  .then => barbie.die()
  .fail => HIMYM = Factory("serie")

If you want to have barbie

me = new Man()
barbie = new PerfectWoman()

you are not Ken, so you will have to work hard

$.when(me.find("job"), me.do("sport"), 
  me.earn("money"), me.do("surgery"))
  .then => me.marry(barbie)
  .then => child = Sex(me, barbie)
  .then(child) => me.takeCare(child)
  .then => me.die()
  .then => barbie.die()
  .fail(error) => me.find("otherWoman")

So what is the link with JS?

It's the same thing!

Code is just a story

Some examples

Classic workflow in node

user.findWhere(name:"john").success(user) ->
  Email.send(user.email).success(response) ->
    fs.write response, (status) ->
      user.save(status: "message send"). success(err, res) ->
        console.log "workflow finished"

It will be

user.findWhere(name:"john")
  .then (user) -> Email.send(user.email)
  .then (response) -> fs.write response
  .then (status) -> user.save(status: "message send")
  .then (status) -> console.log "Workflow finished"

If you need data in several place

Example with backbone

checkAllFetched = (collection) =>
  collection.fetched = true
  if @collection1.fetched and @collection2.fetched
    @prepareData()
fetchOptions =
  success: checkAllFetched
  data: @params
@collection1.fetch fetchOptions
@collection2.fetch fetchOptions

turn with promise

$.when(@collection1.fetch(data: @params), 
  @collection2.fetch(data: @params))
  .done => @prepareData()

How to convert into a promise?

With Q

classic database search with node

find: (email, callback) ->
  @query "SELECT `id`, `email` WHERE email = `?` LIMIT 1", email, (err, res) ->
    callback err, res[0]

Turn into promise

find: (email) ->
  deferred = Q.defer()
  @query "SELECT `id`, `email` WHERE email = `?` LIMIT 1", 
    email, (err, res) ->
    if err
      deferred.reject new Error(err)
    else
      deferred.resolve res
  return deferred.promise

shorter notation

find (email) ->
Q.nfcall @query, "SELECT `id`, `email` WHERE email = `?` LIMIT 1", email

or

find (email) ->
Q.ninvoke @, "query", "SELECT `id`, `email` WHERE email = `?` LIMIT 1", email

How to convert into a promise?

With jQuery

It is here since jQuery 1.5

With the object defered

Turn async function into promise

promiseFunc = ->
  deferred = new jQuery.Deferred()
  ayncFunction param, (err, res) ->
    if err
      deferred.reject err
    else
      deferred.resolve res
  return deferred.promise()

It will be used

$.when(promiseFunc).then ((res) ->
  alert status + ", things are going well"

With existing jQuery method

$.when($.get("http://url.com"))
  .then (data) ->
    alert data + ", things are going well"
  .fail (err) ->
    console.log err

Links

Question?

THE END

BY Fabien Garcia