Skip to content

Chain instructions for mutating the fulfillment value of a not yet constructed promise.

License

Notifications You must be signed in to change notification settings

jogemu/promisemut

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

promisemut

Chain instructions for mutating the fulfillment value of a not yet constructed promise. This package allows to easily break promise chains into smaller, more manageable functions. Mutators for objects are described intuitively by using an object as a template. It is possible to perform array operations directly on array promises.

Although this could be implemented without promises, they make sense here because of the intuitive data flow. Furthermore, it allows a mutator to return a promise.

Getting started

Let's make the following code return the modified object instead. It may be necessary to get familiar with promises and arrow functions.

Promise.resolve({ age: 0 }).then(
  (value) => value.age += 1
).then(console.log)
// Output: 1

The function can be simply wrapped in mutate.

import resolve from 'promisemut'

Promise.resolve({ age: 0 }).then(
  resolve.mutate((value) => value.age += 1)
).then(console.log)
// Output: { age: 1 }

Since this assigns a new value to age it can be described through a template object that has an independent function for each key.

import resolve from 'promisemut'

Promise.resolve({ age: 0 }).then(
  resolve.assign({
    age: (value) => value + 1
  })
).then(console.log)
// Output: { age: 1 }

It is simple to make the function easily reusable.

let increaseAge = resolve.assign({
  age: (value) => value + 1
})

increaseAge({ age: 0 }).then(console.log)
// Output: { age: 1 }

The template can access the object as well.

let needsMaintenance = resolve.assign({
  maintained: (value, key, item) => item.age < 1
})

needsMaintenance({ age: 0 }).then(console.log)
// Output: { age: 0, maintained: true }

The two previous functions can be easily combined.

let needsMaintenanceSoon = increaseAge.then(needsMaintenance)

needsMaintenanceSoon({ age: 0 }).then(console.log)
// Output: { age: 1, maintained: false }

In case the original object should not be modified, use then instead of assign.

Arrays

let array = resolve
  .filter('age')   // [ {age: 1}, {age: 2} ]
  .reverse()       // [ {age: 2}, {age: 1} ]
  .map(o => o.age) // [ 2, 1 ]
  .sort()          // [ 1, 2 ]
  .map({
    age: (...[,,a]) => a,
    valid: true
  })               // [ { age: 1, valid: true }, { age: 2, valid: true } ]
  .then(console.log)

array([{age: 0}, {age: 1}, {age: 2}])

It is possible to map objects as well (index = key).

Advanced

Many advantages of this approach only become apparent when the mutator requires arguments that do not traverse through the promise chain.

let increaseAge = increment => resolve.assign({
  age: (value) => value + increment
})

promise.then(increaseAge(2)).then(console.log)

There is direct access to the resolve function as well. It can be called like promise.then(resolve.then(fn)) to allow to work with a fulfilled like it is a promise. All other functions are built on that and support to be called directly on resolve like resolve.mutate(fn).mutate(fn) instead of resolve.then(mutate(fn).then(mutate(fn))). The value resolve receives can be accessed later in the chain with then2. This works similarly to the argument of the mutator above but this time the argument is dynamic.

About

Chain instructions for mutating the fulfillment value of a not yet constructed promise.

Topics

Resources

License

Stars

Watchers

Forks