# Javascript Cheat Sheet ## Snippets ### Promise Delay Waits a certain amount of time, then returns with a promise #### Code ```javascript let waitAWhile = (timeToWait) => new Promise(resolve => setTimeout(resolve, timeToWait)); ``` ## Arrays ### Split Array into chunks Does not mutate the original array #### Code ```javascript const chunk = (collection, length) => collection.length === 0 ? [] : [collection.slice(0, length)].concat(chunk(collection.slice(length), length)); ``` or a more compact one-liner ```javascript const chunk = (a, l) => a.length === 0 ? [] : [a.slice(0, l)].concat(chunk(a.slice(l), l)); ``` #### Usage ```javascript 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 ```javascript 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 ```javascript 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 ```javascript 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 ```javascript 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. ```javascript // 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 ```javascript // 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); ```