Skip to content

Instantly share code, notes, and snippets.

@robotlolita
Last active October 19, 2015 22:58
Show Gist options
  • Save robotlolita/39d8ebab7534bdf566c9 to your computer and use it in GitHub Desktop.
Save robotlolita/39d8ebab7534bdf566c9 to your computer and use it in GitHub Desktop.

Nested asynchronous objects are a problem with Promises/A+, since you can't nest promises.

Compare Data.Task:

function AsyncMap() {
  this.data = {}
}
// :: String, a -> Task<b, Unit>
AsyncMap.prototype.set = function(key, value) {
  return new Task(function(_, resolve) {
    this.data[key] = value
    resolve()
  })
}
// :: String -> Task<Error, a>
AsyncMap.prototype.get = function(key, value) {
  return new Task(function(reject, resolve) {
    if (key in this.data)  resolve(this.data[key])
    else                   reject(new Error(key + ' not found'))
  })
}

var x = new AsyncMap()
x.set('foo', Task.of(1))
x.get('foo').map(identity) // => Task(1)

With Promises/A+:

function AsyncMap() {
  this.data = {}
}
// :: String, a -> Promise<b, Unit>
AsyncMap.prototype.set = function(key, value) {
  return new Promise(function(_, resolve) {
    this.data[key] = value
    resolve()
  })
}
// :: String -> Promise<Error, a>
AsyncMap.prototype.get = function(key, value) {
  return new Promise(function(reject, resolve) {
    if (key in this.data)  resolve(this.data[key])
    else                   reject(new Error(key + ' not found'))
  })
}

var x = new AsyncMap()
x.set('foo', Promise.of(1))
x.get('foo').then(identity) // => 1

To get the promise-based version to work correctly you need to wrap all values:

function Wrap(v) {
  this.value = v
}
function AsyncMap() {
  this.data = {}
}
// :: String, a -> Promise<b, Unit>
AsyncMap.prototype.set = function(key, value) {
  return new Promise(function(_, resolve) {
    this.data[key] = value
    resolve()
  })
}
// :: String -> Promise<Error, Wrap<a>>
AsyncMap.prototype.get = function(key, value) {
  return new Promise(function(reject, resolve) {
    if (key in this.data)  resolve(new Wrap(this.data[key]))
    else                   reject(new Error(key + ' not found'))
  })
}

var x = new AsyncMap()
x.set('foo', Promise.of(1))
x.get('foo').then(identity) // => Wrap(Promise(1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment