Open8
JavaScript小片
引数のプロミスを関数内で展開する。
プロミスに対応した自乗関数
const square = (valueOrPromise) => {
if (typeof valueOrPromise?.then === 'function') {
return valueOrPromise.then(square);
}
const value = valueOrPromise;
return value * value;
}
Promise.withResolvers()
もどき。
Promise.withResolvers もどき
const withResolvers = () => {
let resolve, reject;
const promise = new Promise((resolve_, reject_) => {
resolve = resolve_;
reject = reject_;
});
return { promise, resolve, reject };
};
使用例。
一定期間の待ちを発生させる関数
const wait = (timeout) => {
const { promise, resolve } = withResolvers();
setTimeout(resolve, timeout);
return promise;
};
タイムアウト
既存の非同期関数にタイムアウトを追加する
const withTimeout = (timeout, asyncTask) => {
return (...args) => {
const { promise, reject } = Promise.withResolvers();
setTimeout(() => reject(new Error('timed out')), timeout);
return Promise.race([asyncTask(...args), promise]);
};
};
フィルタ関数
フィルタ関数
const filter = function *(iterable, f) {
for (const value of iterable) {
if (f(value)) yield value;
}
};
オーバーライドの確認
オーバーライドの確認
const isOverridden = (o, key) => {
if (o == null || typeof o !== 'object') { return false; }
let has = false;
for (let p = o; p != null; p = Object.getPrototypeOf(p)) {
if (!Object.hasOwn(p, key)) { continue; }
if (!has) {
has = true;
} else {
return true;
}
}
return false;
};
汎用のプロパティ記述子取得関数
汎用のプロパティ記述子取得関数
const getPropertyDescriptor = (o, key) => {
if (o == null || typeof o !== 'object') { return {}; }
const k = typeof key === 'string' || typeof key === 'symbol' ? key : String(key);
let descriptor;
let owner = o;
for (; owner != null; owner = Object.getPrototypeOf(owner)) {
descriptor = Object.getOwnPropertyDescriptor(owner, k);
if (descriptor != null) { break; }
}
return owner == null || descriptor == null ? {} : { owner, descriptor };
};
関数にログ出力を後付で追加する。
ロガーの設定
const withLogger = (f, logger) => {
const log = logger ?? (...args) => console.debug(...args);
return new Proxy(f, {
construct: (target, args, newTarget) => {
log(f.name, 'new', { target, args, newTarget });
const result = new target(...args);
log(f.name, 'new', { result });
const methods = new WeakMap();
return new Proxy(result, {
get: (target, key, receiver) => {
log(f.name, 'get', key, { target, receiver });
// https://zenn.dev/link/comments/cb9f30fd9fa106
const { descriptor } = getPropertyDescriptor(target, key);
const get = descriptor?.get;
const value = get ?? descriptor?.value;
if (typeof value !== 'function') {
log(f.name, 'get', key, { value });
return value;
} else {
let method = methods.get(value);
if (method == null) {
method = withLogger(value, log);
methods.set(value, method);
}
return (get != null) ? method.apply(target) : method;
}
}
});
},
apply: (target, thisArg, args) => {
log(target.name, 'apply', { thisArg, args });
const result = target.apply(thisArg, args);
log(target.name, 'apply', { thisArg, result });
return result;
}
});
};
Promise対応関数化する関数
Promise対応関数化する関数
const asPromiseAware = (f) => {
const f_ = {
[f.name]: function(...args) {
return args.some(x => (typeof x?.then === 'function')) ?
Promise.all(args).then(xs => f_.apply(this, xs)) :
f.apply(this, args)
;
}
}[f.name];
return f_;
};
作成者以外のコメントは許可されていません