Skip to content

Instantly share code, notes, and snippets.

@wjvander
Last active April 4, 2018 10:37
Show Gist options
  • Save wjvander/cffd450bfe6fa7dc4b89a9c1ddc2048c to your computer and use it in GitHub Desktop.
Save wjvander/cffd450bfe6fa7dc4b89a9c1ddc2048c to your computer and use it in GitHub Desktop.
Javascript Cheat Sheet

Javascript Cheat Sheet

Snippets

Promise Delay

Waits a certain amount of time, then returns with a promise

Code

let waitAWhile = (timeToWait) => new Promise(resolve => setTimeout(resolve, timeToWait));

Arrays

Split Array into chunks

Does not mutate the original array

Code

const chunk = (collection, length) => collection.length === 0 
  ? [] 
  : [collection.slice(0, length)].concat(chunk(collection.slice(length), length));

or a more compact one-liner

const chunk = (a, l) => a.length === 0 ? [] : [a.slice(0, l)].concat(chunk(a.slice(l), l));

Usage

let someArray = [1, 2]
let chunkSize = 10
let chunks = chunk(someArray, chunkSize)

Async/Await batching of Array

Description

It runs batches synchronously, but async for each item in a batch. Might be a good idea to just do a try...catch inside the map.

Code

let batches = chunk(myArray, 10)
for(let batch of batches){
  await Promise.all(batch.map(async(item) => {
    await doSomeAsyncStuffForEachItemInBatch(item);
  }));
})

Refactorings

Switch Statements

Description

You have a switch statement, but it is ugly and not easy to maintain.

Original

let mySwitchCase = (code) => {
  switch (code) {
    case '101': {
      return 'one-o-one';
    }
    case '102': {
      return 'one-o-two';
    }
    default: {
      return 'defaultValue';
    }
  }
}

Attempt 1

You could turn it into an object lookup, but then it a default value would be more complicated

let myCases = {
'101': 'one-o-one',
'102': 'one-o-two'
};

let text = myCases['101']; // one-o-one
let text = myCases['10000'] || 'defaultValue'; // defaultValue

Attempt 2

I like the object lookup idea, but having to check if it returned a value each time just to declare a default is not nice. So I could wrap it in a function

let myCases = (code) => {
  let cases = {
    '101': 'one-o-one',
    '102': 'one-o-two'
  };
  
  return cases[code] || 'defaultValue';
};

let text = myCases('101'); // one-o-one
let text = myCases('10000'); // defaultValue

Attempt 3

So I like the idea of an object lookup and wrapping it in a function, which is fine for one case, but if I have multiple of these, I have to keep writing the function, the cases and the logic check...this smells a bit. So I can extract it even more, so that the logic is only written once for each switch case.

This also means that the cases no longer have to be hard coded, we could load them from a JSON file, dynamically create them etc. This gives us a lot more flexible code.

// You declare a function that can return a specified key or a default value and curry the hell out of it
const switchCase = cases => defaultCase => key =>
  cases.hasOwnProperty(key) ? cases[key] : defaultCase;
  
// you can then declare your cases with a default like so
const mySwitchCases = switchCase({
  '101': 'one-o-one',
  '102': 'one-o-two'
})('defaultValue');

// you can then use it as such
let text = mySwitchCases('101'); // 'one-o-one'
let text = mySwitchCases('100000'); // 'defaultValue'

Design Patterns

Chain of Responsibility

Use cases

  • When there are multiple handlers for a request but you are unsure of which one will handle the request
  • When there is a list of handlers that should handle a request
  • Handlers are dynamically defined

Code

// Handler Super Class
class RequestHandler {
  constructor(){
    this.next = {
      console.log('End of pipeline');
      return Promise.resolve();
    }
  }
  
  setNext(next){
    this.next = next;
    return next;
  }
  
  async handleRequest(request){}
}

// Some handler
class MyHandler extends RequestHandler{
  constructor(someDependency){
    super();
    this.something = someDependency;
  }
  
  // Super class override
  async handleRequest(request){
    // do something here
    // if you want to stop the pipeline, return, otherwise pass request to next
    // This is not needed if you want all handlers to receive the request
    
    if (shouldStopHere)
      return;
      
    await this.next.handleRequest(request);
  }
}

// How to use
// Declare all your handlers, they can be different handlers, as long as they extend RequestHandler
let myHandler = new MyHandler(someDependency);
let mySecondHandler = new MyHandler(someDependecy);
let myThirdHandler = new MyOtherHandler();

// Define the order in which the handlers will execute ie. pipeline
myHandler
  .setNext(mySecondHandler)
  .setNext(myThirdHandler);

// Start the pipeline
myHandler.handleRequest(someRequest);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment