Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[SAPUI5] Promisify an oData request

This is discussed for many years and unfortunately will not be implemented in the UI5 framework itself (see here). There are already different blogs describing how to build a wrapper for oData requests (for example here and here).

But with ES2024 it now got super simple to do this:

async function readData(model, entitySet) {
  const [promise, resolve, reject] = Promise.withResolver( )
  model.read(entitySet, {
    success: data => resolve(data),
    error: error => reject(error)
  })
  return promise
}

const user = await readData(oDataModel, "/user")

[JavaScript] Working with Promises in 2024

Since ES2024 there is a new way to create promises by using the withResolver function:

// ES 6 Via Constructor
const promise = new Promise((resolve, reject) => { }

// ES2024 Via factory function
const [promise, resolve, reject] = Promise.withResolver( )

Since ES2018 there is an additional handler called finally:

const promise = fetch("/myAPI")

promise
  .then(response => console.log(response))
  .catch(error => console.error(error))
  .finally(() => console.log("Called in any case"))

And handling multiple Promises has been made easier by the new methods allSettled, any, race which were introduced in ES2020 and ES2015:

// Promise that resolves when all promises are resolved
const promise = Promise.all([promiseA, promiseB])
promise.then(([valueA, valueB]) => console.log(valueA, valueB))

// ES2020 Promise that resolves when all promises are settled (either resolved or rejected)
const promise = Promise.allSettled([promiseA, promiseB])

// ES2020 Promise that resolves when either promiseA or promiseB is resolved
const promise = Promise.any([promiseA, promiseB])

// ES2015 Promise that resolves/rejects when any promise is resolved or rejected
const promise = Promise.race([promiseA, promiseB])

[JavaScript] ES6

These are my notes while doing the course JavaScript Algorithms and Data Structures on https://www.freecodecamp.org. I highly recommend it if you prefer to try things directly rather than watching videos.


let and const

Variables with the var keyword can be overwritten without an error. With E6 the keyword let was introduced to solve this potential issue.

var camper = 'James';
var camper = 'David'; //no error

let camper = 'James';
let camper = 'David'; // throws an error

"use strict";
x = 3.14; // throws an error because x is not declared

Note: The "use strict" enables Strict Mode, which catches common coding mistakes and “unsafe” actions.


const

Same features as let has + read-only.

const FAV_PET = "Cats";
FAV_PET = "Dogs"; // returns error

Note: Use uppercase variable identifiers for immutable values and lowercase or camelCase for mutable values (objects and arrays).

Objects (including arrays and functions) assigned to a variable using const are still mutable!
Using the const declaration only prevents reassignment of the variable identifier. You can not use the variable identifier to point to a different array, but the elements are mutable.

const s = [10, 11, 12];
s = [1, 2, 3]; // throws error, trying to assign a const
s[2] = 45; // works just as it would with an array declared with var or let
s.pop(45); //also works fine

Prevent Object Mutation with function Object.freeze()


Arrow Functions

If you don’t reuse a function you don’t need a name for it, especially when passing a function as an argument to another function.

var magic = function() {
  return new Date();
};

/* arrow function syntax */
const magic = () => {
  return new Date();
};

/* If there is no function body and only a return, omit the keyword return as well as the backets */
const magic = () => new Date();

Arrow Functions with Parameters

const doubler = (item) => item * 2;
doubler(6); // returns 12

/* If you have a single parameter, omit the parentheses */
const doubler = item => item * 2;

const multiplier = (item, multi) => item * multi;
multiplier(6, 2); // returns 12

Default Parameters

The default parameter is used when the argument is not specified (is undefined).

const hello = (name = "World") => "Hello " + name;

console.log(hello("Mars")); // Hello Mars
console.log(hello()); // Hello World

Rest Parameter

With the rest parameter, you can create functions that take a variable number of arguments. These arguments are stored in an array.

function howMany(...arguments) {
  return "You passed " + arguments.length + " arguments.";
}
console.log(howMany(0, 1, 2)); // You passed 3 arguments.

Spread Operator

The spread operator allows us to expand arrays and other expressions in places where multiple parameters or elements are expected. I.e. Math.max() expects comma-separated arguments, but not an array. The spread operator unpacks all contents of an array into a comma-separated list. To pick specific elements, better use array destructuring.

const array = [2, 99, 7, 4];

/* workaround in ES5 */
var max = Math.max.apply(null, array); // returns 99

/* ES6 */
const max = Math.max(...array); // returns 99

Destructuring Assignment

Destructuring assignment is special syntax for neatly assigning values taken directly from an object,

const person = { name: 'Max', age: 30 };

/* ES5 */
const name = person.name; // name = 'Max'
const age = person.age; // age = 30

/* ES6 */
const { name, age } = person; // name = 'Max', age = 30
// It even allows you to assign a new variable name
const { name: personName, age: personAge } = user; // personName = 'Max', personAge = 30

or from an array.

const [a, b,,, c] = [1, 2, 3, 4, 5, 6, 7];
console.log(a, b, c); // 1, 2, 5

// or collect the rest of the elements into a separate array
const [a, b, ...array] = [1, 2, 3, 4, 5, 7];
console.log(a, b); // 1, 2
console.log(array); // [3, 4, 5, 7]

Destructuring Assignment to Pass an Object as a Function’s Parameters.

const stats = {
  max: 56.78,
  standard_deviation: 4.34,
  median: 34.54,
  mode: 23.87,
  min: -0.75,
  average: 35.85
};

const half = ({max, min}) => (max + min) / 2.0; 

Template Literals

Template literal is a special type of string that makes creating complex strings easier.

const person = {
  name: "Zodiac Hasbro",
  age: 56
};

const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;

console.log(greeting); // prints
// Hello, my name is Zodiac Hasbro!
// I am 56 years old.

Concise Object Literal Declarations

Short way to define object properties.

const createPerson = (name, age, gender) => {
  return {
    name: name,
    age: age,
    gender: gender
  };
};

/* Eliminates the redundancy of having to write x: x */
const createPerson = (name, age, gender) => ({
    name,
    age,
    gender
  });

Concise Declarative Functions

Remove the function keyword and colon when defining functions in objects.

/* ES5 function declaration */
const person = {
  name: "Max",
  sayHello: function() {
    return `Hello! My name is ${this.name}.`;
  }
};

/* ES6 */
const person = {
  name: "Max",
  sayHello() {
    return `Hello! My name is ${this.name}.`;
  }
};
person.sayHello();

class Syntax to Define a Constructor Function

New syntax to create objects, using the class keyword. The class syntax replaces the constructor function creation. The new keyword is used to instantiate an object.

/* ES5 */
var SpaceShuttle = function(targetPlanet){
  this.targetPlanet = targetPlanet;
}
var zeus = new SpaceShuttle('Mars');


/* ES6 */
class SpaceShuttle {
  constructor(targetPlanet) {
    this.targetPlanet = targetPlanet;
  }
}
const zeus = new SpaceShuttle('Mars');

Note: The class syntax should not be confused with a full class-based implementation of an object-oriented paradigm.


getters and setters to Control Access to an Object

class Thermostat {
    constructor(temperatureFahrenheit) {
        this._temperatureCelsius = 5/9 * (temperatureFahrenheit - 32);
    }
    //getter
    get temperature() {
        return this._temperatureCelsius;
    }
    //setter
    set temperature(updateTemperatureCelsius) {
        this._temperatureCelsius = updateTemperatureCelsius;
    }
}

const thermos = new Thermostat(76); // Setting in Fahrenheit scale
let temp = thermos.temperature; // 24.44 in Celsius
thermos.temperature = 26; // use setter
temp = thermos.temperature; // 26 in Celsius

Note: It is convention to precede the name of a private variable with an underscore _


Module Script

A way to easily share code among JavaScript files. Export parts of a file and import the parts you need, where you need them.
You need to create a script in your HTML document with a type of module.

<script type="module" src="string_functions.js"></script>
const uppercaseString = (string) => string.toUpperCase();
const lowercaseString = (string) => string.toLowerCase();

export {uppercaseString, lowercaseString};
/* import specific functions */
import { uppercaseString, lowercaseString } from './string_functions.js';

uppercaseString("hello");
lowercaseString("WORLD!");

/* import all */
import * as stringFunctions from './string_functions.js';
stringFunctions.uppercaseString("hello");
stringFunctions.lowercaseString("WORLD!");

Promise

Use it to make a promise to do something, usually asynchronously. Promise is a constructor function, so you need to use the new keyword to create one. It takes a function, as its argument, with two parameters – resolve and reject.
When you make a server request it takes some amount of time, and after it completes you usually want to do something with the response from the server. This can be achieved by using the then method. The then method is executed immediately after your promise is fulfilled with resolve.

const makeServerRequest = new Promise((resolve, reject) => {
  // responseFromServer represents a response from a server
  let responseFromServer;
    
  if(responseFromServer) {
    resolve("We got the data");
  } else {  
    reject("Data not received");
  }
});

makeServerRequest.then(result => {
  console.log(result);
})

makeServerRequest.catch(error => {
  console.log(error);
});