Promise
The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
Therefore we can let an asynchronous method to return as a synchronous method. We can associate handlers to the promise. These handlers will handle eventaul success values or failure reason.
A promise has three states: pending, fulfilled with a value or rejected with a reason.
We use then method of promise object to attach handler.
Consuming promise
promiseObj.then(successCallBackFunc, failureCallbackFunc)
Guarantees for then()
- then will never be invoked if promise is in pending state
- then will be called event if it is added after promise has exited from pending state
- can add multiple then. These thens will be called in the order they are added
promise.catch()
return a promise and deals with rejected case only. It is the same as to call then(undefined, onRejected)
promise.finally()
- the finally() method is executed when the promise is settled no matter it is successful or failed
- This handler of finally receives no parameters
- It will return another promise
Creating Promise
Promise.resolve(value) will return
- A promise that is resolved by value passed as argument
- If value passed as argument is a promise, will return that promise
Promise.reject(reason) will return
A promise object that is rejected with a given reason
Promise.all()
The argument of all is an array of promise. It will return one promise. This returned promise fulfills when
all of the input's promises fulfill (including when an empty iterable is passed), with an array of the fulfillment
values. It rejects when any of the input's promises rejects, with this first rejection reason.
The Promise.race() static method takes an iterable of promises as input and returns
a single Promise. This returned promise settles with the eventual state of the first promise
setTimeout(functionRef, delay, param1) delay unit is millisecond
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'tuttle');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'rabit');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// Expected output: "rabit"
//Promise in action
//Promise constructor accepts two predefined
//functions: resolve and reject
let p = new Promise((resolve, reject)=> {
let good = false
if (good) {
resolve(100)
} else {
reject("sad. bad")
}
});
//we will see sad. bad. However, if we set good to be true,
//will see 101. Here then accepts two functions. The first is
//for fulfillment and the second is for rejection
p.then((n)=> console.log(n+1), (msg)=>console.log(msg))
//here is another way
p.then((n)=> {
console.log("resolved")
console.log("n", n+1)
}).catch((msg) => {
console.log("rejected")
console.log("msg", msg)
})
Put axios in a Promise chain
//sample codes to put axios in a Promise chain
session.onpaymentauthorized = (event)=> {
applePayInstance.tokenize({
token: event.payment.token
}).then( (payload) => {
const requestData = {
url: '/test/do-whatever/',
method: 'post',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: "amount=111"
}
//return another promise and it will be put in this chain
return axios(requestData)
}).then(response => {
if (response.data.success){
console.log("good. will complete sesson to dismiss sheet")
} else {
console.log("creating order failed")
}
}).catch((tokenizeErr) => {
console.log('Error tokenizing Apple Pay:', tokenizeErr);
session.completePayment(ApplePaySession.STATUS_FAILURE);
});
};
//an example to use axios
//an example to use axios
import axios from "axios";
let postData = {
name: "john",
age: 35,
};
const requestData = {
url: '/myulr/test/?eventName=' + eventName,
method: 'post',
headers: {
'content-type': 'application/json',
'x-requested-with': 'XMLHttpRequest'
},
data: postData
}
axios(requestData)
//server side to invoke by node.js
const axios = require('axios');
//to debug
axios(requestData).catch((err) => {
console.log(err.response)
})
Use async function to handle promise
An async function is a function declared with the async keyword. It works with await keywords to handle promise in a cleaner style. Await and async will not block javascript main thread. await will wait a result of a promise.
Here is an example:
myPromiseGenerator = function() {
return new Promise(resolve => {
setTimeout(() => {
resolve('Hello world');
}, 2000);
});
}
async function myFunc() {
console.log('calling');
//waiting for promise result
const result = await myPromiseGenerator();
console.log(result);
}
myFunc()
//output will be the following
//calling
//Hello world
Object.assign
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// Expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget)
// Expected output: Object { a: 1, b: 4, c: 5 }
console.log(source)
// Expected output: Object { a: 1, b: 2} . no change from origin
for ..of loops
ES6 adds a for ..of loop. It is used to loop of set of values produced by an iterator. Most likely, will be used to loop
through array and string
var arr = ['a','b','c']
for (var val of arr) {
console.log(val)
}
//'a', 'b', 'c'
for (var c of 'hi') {
console.log(c)
}
//'h', 'i'
//loop array index
for (let i in arr) {
console.log(i)
}
//0,1,2
use object as hash table
The below is a solution for a LeetCode problem
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function(nums) {
//define a object
let d = {}
for (let n of nums) {
//check if n is a property of object. like check if hash has key
if (n in d) {
d[n] = 2
} else {
d[n] =1
}
}
//loop through object's property
for (let n in d) {
if (d[n]==1) {
return n;
}
}
//if want to get all properties of this object
let keys = Object.keys(d)
// get length
Object.keys(obj).length
};
Build array of objects
//build offer array
let offerVals = []
for (let offer of data.offers) {
let obj = {}
obj[offer.sku] = offer.quantity
offerVals.push(obj)
}
//build json string with array. noted that build obj in two ways
//output {"category":"developers","persons":[{"name":"leo","age":50},
//{"name":"john","age":40}]}
let obj = [];
obj.push({ name: "leo", age: 50 });
let p2 = {};
p2["name"] = "john";
p2["age"] = 50;
obj.push(p2);
let str = { category: "developers", persons: obj };
console.log(JSON.stringify(str));
ES6 template literals
Use backtick ` as delimiter.
let name="leo"
let welcome = `hi ${name}!`;
console.log(welcome) //hi leo!
//allow split across multiple lines
let name=`hello
world`;
//hello
//world
console.log(name)
Array
//sort number array
nums.sort((a,b)=>a-b)
//initiate array with single values
// arr = Array(arraySize).fill(value)
let ans = Array(5).fill(-1)
//copy array
const animals = ['dog', 'bison', 'camel', 'duck', 'elephant'];
let animalCopy = animals.slice();
//also can do the following to copy
let animalCopy = [].concat(animals)
//array merge
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const arr3 = ['j','p']
const array4 = array1.concat(array2, arr3);
//array4 is ['a', 'b', 'c','d', 'e', 'f','j','p']
//unshift to add element in the begining of array
const array1 = [1, 2, 3];
array1.unshift(4, 5);
console.log(array1);
// expected output: Array [4, 5, 1, 2, 3]
//map() will create a new array by calling a provided function for every elements
const arr1 = [1, 2, 3]
const arr2 = arr1.map((n)=>n*n)
console.log(arr2) //[1,4,9]
//use filter to move element to the begin of array. Here assume p is in array and it is unique
arr = arr.filter(item => item !== q);
arr.unshift(q);
//create a 26 letters array
const letters = 'abcdefghijklmnopqrstuvwxyz'.split('');
//string to array
let s ="leetcode"
const chars = [...s];
Object destructuring
const pet = {name:"weiwei", age:13}
//here is object destructuring
const {name, age} = pet
console.log("name", name)
console.log("age", age)
//Destruct and Rename
const person = {
name: "leo",
country: "Canada"
}
const {name:first} = person
console.log("first is:", first) //leo
console.log("name:", name) //undefined
Math
// integer division. will get 4
Math.trunc(32/7)
High order component
A good blog about high order component
Four steps
- Create a base component
- Create a function which take base component and return a upgraded component
- import that function and call it to get a new component
- use this new component. This new component normally has new extra props
Redux form is high order component. Here is a good introduction for redux form.
Response.json()
The json() method takes a Response stream and reads it to completion. It returns a promise which resolves with the result of parsing the body text as JSON.
Then we can use this data to do some thing. The pattern is showing below which work with fetch.
const remoteEndPoint = "https://someapi";
fetch(remoteEndPoint)
.then((response) => response.json())
.then((data) => {
this.setState({ loading: false, data: data });
})
.catch(console.error);
Use Axios
We can send a header config when do API call using Axios. Noted position of config field for get and post are different.
const config = {
headers: {
"X-Authorization-JWT": initData.jwt,
"Content-Type": "application/json"
}
}
axios.get(url, config)
axios.post(url, data, config)
axios.put(url, data, config)
//to pass csrf and more headers
const config = {
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrf
}
}
lodash
_.includes( collection, value)
let a=[1,2]
let f = _.includes(a, 3) //false
f = _.includes(a,1) //true
Some useful built in function
slice() will do a shallow copy of an array. You can pass indexes as argument of the function. If no argument is passed, do a shallow copy of entire array
const animals = ['ant', 'bison', 'elephant', 'dog'];
console.log(animals.slice());
// expected output: Array ["ant", "bison", "elephant", "dog"]
Object.assign() method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source, {leo:22});
console.log(target);
console.log(returnedTarget);
//output
> Object { a: 1, b: 4, c: 5, leo: 22 }
> Object { a: 1, b: 4, c: 5, leo: 22 }
two ways to copy an object
var player = {score: 1, name: 'Jeff'};
var newPlayer = Object.assign({}, player, {score: 2});
// Now player is unchanged, but newPlayer is {score: 2, name: 'Jeff'}
// Or if you are using object spread syntax proposal, you can write:
// var newPlayer = {...player, score: 2};
Array reduce(). It accept a callback, and will work on every element in order. After done, return the last value. For that callback function, the first argument is the previous value, and the seconde is the current
value. When run on the first element, we can pass an initial value
let arr=[1,2,3]
let iniV = 7
let ans = arr.reduce((total,n)=>total*n, 7)
console.log(ans) //42 = 7*1*2*3
If initial value is not provided, the first element will be used as init value and process element starting from the second element.
let arr=[1,2,3]
let ans = arr.reduce((total,n)=>total*n)
console.log(ans)//6=1*2*3
mapping letter to integer. 'A' =>1 A has value 65
columnTitle.charCodeAt(i)-64
cast type
let a="8"
let b = +a
console.log(typeof a) //string
console.log(typeof b) //number
Optional chaining (?.)
In most use case, try to access an property of object. If it does not exist, return undefined instead of giving out error.
const obj = {
cat: {
name: 'Dinah'
}
};
console.log(obj.cat2?.name);
// expected output: undefined
console.log(obj.cat2.name);
//expected error
console.log(obj.cat.name);
//Dinah
Use [key] notation for object
const name = "leo"
const obj = {[name]:"developer"}
console.log(obj.leo)
console.log(obj[name])
//undefined
console.log(obj.name)
char, int, ascii code
//solution for Leetcode 2194
var cellsInRange = function(s) {
let c1 = s.charCodeAt(0)
let c2 = s.charCodeAt(3)
//0 ascii code is 48
let r1 = s.charCodeAt(1) - 48
let r2 = s.charCodeAt(4) -48
let ans = []
for (let c=c1; c<=c2; c++) {
for (let r=r1; r<=r2; r++) {
//ascii code to char
let cell = String.fromCharCode(c) + r
ans.push(cell)
}
}
return ans
};
Logic or
//The Logical OR operator (||) returns the value of its
//second operand, if the first one is falsy, otherwise the value
//of the first operand is returned
let a ="foo" || "bar"; // returns "foo"
console.log(a)
a = false || "bar"; // returns "bar"
console.log(a)
window.dataLayer = window.dataLayer || [];
Class
Solution for Leetcode 2622
var TimeLimitedCache = function () {
this.d = {};
};
/**
* @param {number} key
* @param {number} value
* @param {number} time until expiration in ms
* @return {boolean} if un-expired key already existed
*/
TimeLimitedCache.prototype.set = function (key, value, duration) {
let ans = false;
if (key in this.d) {
let obj = this.d[key];
if (obj.expiry >= Date.now()) ans = true;
}
this.d[key] = { v: value, expiry: duration + Date.now() };
return ans;
};
/**
* @param {number} key
* @return {number} value associated with key
*/
TimeLimitedCache.prototype.get = function (key) {
if (key in this.d) {
let obj = this.d[key];
return (obj.expiry >= Date.now()) ? obj.v : -1
}
return -1;
};
/**
* @return {number} count of non-expired keys
*/
TimeLimitedCache.prototype.count = function () {
let ans = 0;
let keys = Object.keys(this.d);
for (let k of keys) {
if (this.d[k].expiry >= Date.now()) ans = ans + 1;
}
return ans;
};
/**
* Your TimeLimitedCache object will be instantiated and called as such:
* var obj = new TimeLimitedCache()
* obj.set(1, 42, 1000); // false
* obj.get(1) // 42
* obj.count() // 1
*/
Solution for Leetcode 2695
/**
* @param {number[]} nums
*/
var ArrayWrapper = function(nums) {
this.nums = nums
};
ArrayWrapper.prototype.valueOf = function() {
return this.nums.reduce((a, b) => a + b, 0)
}
ArrayWrapper.prototype.toString = function() {
return `[${this.nums.join()}]`
}
/**
* const obj1 = new ArrayWrapper([1,2]);
* const obj2 = new ArrayWrapper([3,4]);
* obj1 + obj2; // 10
* String(obj1); // "[1,2]"
* String(obj2); // "[3,4]"
*/
Some mistakes
The below is solution for Leetcode 2627
Scope problem. use pendingF = [] instead of let pendingF = []. Without let, pendingF becomes a global variable. Because Leetcode
will run bunches of test, pendingF is accessed by all tests and it causes a hard fix bug.
/**
* @param {Function} fn
* @param {number} t milliseconds
* @return {Function}
*/
var debounce = function (fn, t) {
//make sure this variable is not global. Need let
let pendingF = [];
return function (...args) {
let cur = Date.now();
for (let obj of pendingF) {
if (obj.start > cur) {
clearTimeout(obj.timeout);
}
}
myTimeout = setTimeout(() => fn(...args), t);
pendingF.push({ timeout: myTimeout, start: cur + t });
};
};
/**
* const log = debounce(console.log, 100);
* log('Hello'); // cancelled
* log('Hello'); // cancelled
* log('Hello'); // Logged at t=100ms
*/
Sort Array
Sort Array
Play with object
/**
* @param {Object} obj
* @return {Object}
* Leetcode 2822
*/
var invertObject = function (obj) {
let ans = {};
for (let k of Object.keys(obj)) {
let v = obj[k];
if (Object.hasOwn(ans, v)) {
let cur = ans[v];
if (Array.isArray(cur)) {
cur.push(k);
} else {
cur = [cur];
cur.push(k);
}
ans[v] = cur;
} else {
ans[v] = k;
}
}
return ans;
};
Set
let set = new Set();
set.add(1);
set.add(1);
set.add(2);
set.add(100);
//size is 3
console.log(set.size);
Debug
Safari
- right click page. select inspect element to show console
- click recycle bin in the upper right corner to clear console
Chrome
- right click page. select inspect to show console
- type console.clear() to clear console
package.json
//do not install devDependencies
npm install --production
//will install devDependencies
npm install
jQuery
//ajax call to get data
$.get("http://test.com", function(data, status){
alert("Data: " + data + "\nStatus: " + status);
});
//find first element of a class
$(".myClass").first();
//pass a string containing HTML and create a new element:
let html = "Hi
";
let myEle = $(html);
let parent = $(".myClass").first();
let html = "<div>Hi</div>";
let myEle = $(html);
parent.append(myEle);
Switch node version by nvm
nvm list
# add the following in .bashrc, so alway use the version 16 when open a terminal
nvm use 16.15.1
not null and not undefined
//the followinig two lines are equasl
a != null;
a !==null && a !== undefined;