30 seconds of code
How can I implement a singleton in JavaScript?
- The Proxy object is used to define so-called traps(捕获器)
handler.construct()
, the trap for the new
operator
// Examples
class MyClass {}
const MySingletonClass = singletonify(MyClass);
const myObj = new MySingletonClass();
const myObj2 = new MySingletonClass();
console.log(myObj === myObj2);
const singletonify = (className) => {
return new Proxy(className.prototype.constructor, {
instance: null,
construct(target, args) {
if (!this.instance) {
this.instance = new target(...args);
}
return this.instance;
}
});
}
Where and how can I use memoization in JavaScript?
- use to speed up your code
- uses a cache to store results, so that subsequent calls of time-consuming functions do not perform the same work another time.
- JavaScript's
Proxy object
provides an interesting alternative via the use of the handler.apply()
trap
// Examples
const fibonacci = n => (n <= 1 ? 1 : fibonacci(n - 1) + fibonacci(n - 2));
const memoizedFibonacci = memoize(fibonacci);
for (let i = 0; i < 100; i ++)
fibonacci(30); // ~5000ms
for (let i = 0; i < 100; i ++)
memoizedFibonacci(30);
const memoize = (fn) => {
return new Proxy(fn, {
cache: new Map(),
apply(target, thisArg, argumentsList) {
let cacheKey = argsList.toString();
if (!this.cache.has(cacheKey)) {
this.cache.set(cacheKey, target.apply(thisArg, argumentsList))
}
return this.cache.get(cacheKey);
}
});
}
runAsync
- Runs a function in a separate thread by using a
Web Worker
, allowing long running functions to not block the UI.
const runAsync = (fn) => {
const url = URL.createObjectURL(new Blob([`postMessage((${fn})());`]), {
type: 'application/javascript; charset=utf-8'
})
const worker = new Worker(url);
return new Promise((r, j) => {
worker.onmessage = ({ data }) => {
r(data);
worker.terminate();
};
});
}
// Examples
const longRunningFunction = () => {
let result = 0;
for (let i = 0; i < 1000; i++)
for (let j = 0; j < 700; j++)
for (let k = 0; k < 300; k++) result = result + i + j + k;
return result;
};
runAsync(longRunningFunction).then(console.log); // 209685000000
runAsync(() => 10 ** 3).then(console.log); // 1000
let outsideVariable = 50;
runAsync(() => typeof outsideVariable).then(console.log); // 'undefined'
debouncePromise
- Creates a debounced function that returns a
promise
, but delays invoking the provided function until at least ms
milliseconds have elapsed since the last time it was invoked
// Examples
const fn = arg => new Promise(resolve => {
setTimeout(resolve, 1000, ['resolved', arg]);
});
const debounced = debouncePromise(fn, 200);
debounced('foo').then(console.log);
debounced('bar').then(console.log); // 打印 ['resolved', 'bar'] 两次
const debouncePromise = (fn, ms = 0) => {
let timeoutId;
const pending = [];
return (...args) => new Promise((r, j) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
const currentPending = [...pending];
pending.length = 0;
Promise.resolve(fn.apply(this, args)).then(
value => {
currentPending.forEach(({ resolve }) => resolve(value));
},
reason => {
currentPending.forEach(({ reject }) => resolve(reason));
}
);
}, ms)
pending.push({ resolve: r, reject: j });
});
}
pipeAsyncFunctions
const sum = pipeAsyncFunctions(
x => x + 1,
x => new Promise(resolve => setTimeout(() => resolve(x + 2), 1000)),
x => x + 3,
async x => (await x) + 4
);
sum(5).then(console.log)
const pipeAsyncFunctions = (...fns) => (arg) => {
return fns.reduce((acc, fn)=> acc.then(fn), Promise.resolve(arg))
}