JSのプロキシ:何が地獄?
@Transactional
, @Security
, ....). しかしJavaScriptでは、それは通常使用されるものではありません.かどうか?この記事では、
原理
アイデアは、オリジナルオブジェクトをラップする新しいオブジェクトを作成し、プロパティを取得/設定するなどの基本的な操作を遮断し、再定義することです.
より正確に、我々は目標オブジェクトを
object
, function
, ...). そして、トラップを含んでいるハンドラという名前のオブジェクトに対するインタセプト/再実装をする操作を定義しますget
, set
, ...).以下にこれを再開するイメージを示します.
API
今ではJSでプロキシを実装する方法を見る時間です.APIは単純です
const proxy = new Proxy(target, handler);
The handler
を含むオブジェクトtraps
インタセプトするconst handler = {
get(target, prop, receiver) {
console.log("Getting the property", prop);
return target[prop];
},
set(target, prop, value) {
console.log("Setting the property", prop);
target[prop] = value;
},
};
Note: You can also use the
Reflect
API to implement the proxy.
取消し可能代理人
また、与えられた関数のおかげで取り消されることができるプロキシを作成することも可能です.一度破棄されたプロキシは使用できなくなります.
// `revoke` is the function to revoke the proxy
const { proxy, revoke } = Proxy.revocable(target, handler);
Note: It's not able to restore the Proxy once revoked.
そして、我々は行きます.あなたはAPIを知っています、我々が実装することができる若干の例を見ましょう.
トラップの例
ゲット
では始めましょう
get
トラップ.APIは以下の通りです.get(target, property, receiver)
この例では、ユーザーがオブジェクトに存在しないプロパティにアクセスしようとするとエラーをスローするプロキシを行います.const person = {
firstName: "Bob",
lastName: "TheSponge",
};
const personProxy = new Proxy(person, {
get(target, prop) {
if (!prop in target) {
throw new Error(
`The property ${prop} does not exist in the object`
);
}
return target[prop];
},
});
// Will print: 'Bob'
console.log(personProxy.firstName);
// Will throw an error
console.log(personProxy.unknownProp);
適用
The
apply
トラップは次のようなものです.apply(target, thisArg, argumentsList)
それを説明するために、我々はwithTimerProxy
コールバック実行の持続時間を測定します.function aFunction(param) {
console.log("The function has been called with", param);
return "Hello " + param;
}
function withTimerProxy(callback) {
return new Proxy(callback, {
apply(target, thisArg, argumentsList) {
console.time("Duration");
const result = callback.apply(thisArg, argumentsList);
console.timeEnd("Duration");
return result;
},
});
}
const aFunctionWithTimer = withTimerProxy(aFunction);
// Will print:
// The function has been called with World
// Duration: 0.114013671875 ms
// 'Hello World'
console.log(aFunctionWithTimer("World"));
Note: If you want to see more console API you can read my article .
Note: To do such a functionality, we would probably use an High Order Function instead.
その他トラップ
以下に使用するトラップの一覧を示します.
construct(target, argumentsList, newTarget)
defineProperty(target, property, descriptor)
deleteProperty(target, property)
getOwnPropertyDescriptor(target, prop)
getPrototypeOf(target)
has(target, prop)
isExtensible(target)
ownKeys(target)
preventExtensions(target)
set(target, property, value, receiver)
setPrototypeOf(target, prototype)
パフォーマンス?
最近、私は
react-hook-form
その法案は使用しないことを決めたProxy
パフォーマンスの理由のため、フォームの状態を見る人の追跡のためにもう.演奏はそんなに悪いですか.単純なプロパティの値を取得する際のパフォーマンスコストを測定してみましょう.
私は
benchmark
図書館.以下にスクリプトを実行します.const Benchmark = require("benchmark");
const suite = new Benchmark.Suite();
const person = {
firstName: "Bob",
lastName: "TheSponge",
};
const personProxy = new Proxy(person, {});
suite
.add("native", () => {
person.firstName;
})
.add("proxy", () => {
personProxy.firstName;
})
.on("cycle", (event) =>
console.log(event.target.toString())
)
.run({ async: true });
結果は次のようになります.もちろん、ネイティブの実装は、プロパティにアクセスするだけで高速です.プロキシ実装はネイティブのものよりもずっと遅いです.しかし、それはそんなに悪くないと思います.
あなたがインターネットについて検索する場合は、プロキシのパフォーマンス、一部の人々はそれが開発のためのツールであり、生産に使用すべきではないと言う.個人的には、あなたのユースケース、プロキシを使って処理したいデータ量、必要なパフォーマンスに依存していると思います.あなたは、概念(POC)の証明でそれをテストすることができます.
プロキシに依存するライブラリがあり、これは生産で使用できることを証明します.それらの2つを見ましょう.
Note: It's good to note that the "selling point" of
react-hook-form
is the performance, so it makes sense not to use Proxy.
実使用事例
ソルダージャ
SolidJSは、UIを構築するための宣言的なライブラリです.これは仮想DOM(反応に反して)を使用しません.
コードを書く方法は、以下のようになります.
これは、反応還元剤と同等のストアのプロキシを使用します.
あなたがsolidjsを知らない場合は、それは有望な未来を持ってチェックしてください.
例えば、ここでは簡単です
Counter
コンポーネントimport { createSignal } from 'solid-js';
function Counter() {
const [count, setCount] = createSignal(0);
const increment = () => setCount(count() + 1);
return (
<button type="button" onClick={increment}>
{count()}
</button>
);
}
Note: This is not an exhaustive list of similarities / differences and how to use the library. When I feel more confident, I will try to write an article about it because I think it has a bright future ahead of it.
イマジン
Minimjsでは、不変のデータ構造を作成することができますが、変更可能な方法でデータを変更する可能性を与えてくれます.
例えば、次のようにします.
import product from "immer";
const person = {
firstName: "Bob",
lastName: "TheSponge",
};
const newPerson = produce(person, (p) => {
p.firstName = "Patrick";
p.lastName = "Star";
});
// Will return false
console.log(newPerson === person);
これは、オブジェクトを変異せずに変更を簡素化する便利な方法であり、多くのコピーを行うことなく.const person = {
firstName: "Bob",
lastName: "TheSponge",
address: {
type: "pineapple",
city: "Bikini bottom",
},
};
// It prevents us to make things like
const newPerson = {
...person,
address: {
...person.address,
// Note the uppercase
type: "Pineapple",
},
};
Note:
Redux Toolkit
uses it under the hood to make reducers easier to implement.
結論
プロキシは、多くの機能を有効にすると、それらのおかげで再利用可能ないくつかのロジックを抽出することができます.いくつかのライブラリを使用してコードの実行を最適化します.例えば
react-tracked
and proxy-memoize
その利用 proxy-compare
フードの下で、あなたの再レンダリングを減らします.これらのライブラリは、開発したダイシによって開発されますuse-context-selector
私が記事に記載した図書館.しかし、私はあなたがそれが必要であるとき、ユニークに彼らを使用するよう勧めます.
があるTC39 proposal JavaScriptにネイティブのデコレータを追加するには、いくつかの他の可能性を有効にする見込みがあります.たとえば、機能のログを測定/測定するには、.簡単な方法で
@Logger
or @Performance
(これらの注釈の正しい実装を行う).コメントすることを躊躇しないでください、そして、あなたがより多くを見たいならば、あなたは私に続くことができるか、私のところに行くことができますWebsite .
Reference
この問題について(JSのプロキシ:何が地獄?), 我々は、より多くの情報をここで見つけました https://dev.to/romaintrotard/proxy-in-js-what-the-hell-19d0テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol