구조화 된 복제
HTML 표준에는 개체의 깊은 복제본을 만들 수 있는 내부 구조화 된 복제 / 직렬화 알고리즘 이 포함되어 있습니다. 여전히 특정 내장 유형으로 제한되지만 JSON에서 지원하는 몇 가지 유형 외에도 날짜, RegExps, 맵, 세트, Blob, FileLists, ImageDatas, 스파 스 배열, 유형 배열 등을 지원합니다. . 또한 복제 된 데이터 내에서 참조를 유지하므로 JSON에 오류가 발생할 수있는 순환 및 재귀 구조를 지원할 수 있습니다.
Node.js 지원 : 실험적 🙂
v8
(노드 11 등) 현재 Node.js를의 모듈은 직접 구조 직렬화 API를 노출 하지만,이 기능은 여전히 "실험", 미래의 버전에서 변경 또는 제거 대상으로 표시됩니다. 호환되는 버전을 사용하는 경우 객체 복제는 다음과 같이 간단합니다.
const v8 = require('v8');
const structuredClone = obj => {
return v8.deserialize(v8.serialize(obj));
};
브라우저에서 직접 지원 : 어쩌면 결국? 😐
브라우저는 현재 구조적 클로닝 알고리즘을위한 직접적인 인터페이스를 제공하지 않지만 GitHub의 whatwg / html # 793structuredClone()
에서 전역 함수에 대해 논의했습니다 . 현재 제안했듯이 대부분의 목적으로 사용하는 것은 다음과 같이 간단합니다.
const clone = structuredClone(original);
이것이 제공되지 않으면 브라우저의 구조화 된 클론 구현은 간접적으로 만 노출됩니다.
비동기 해결 방법 : 사용 가능 😕
기존 API로 구조화 된 복제본을 만드는 오버 헤드가 낮은 방법은 MessageChannels의 한 포트를 통해 데이터를 게시하는 것 입니다. 다른 포트는 message
연결된의 복제 된 클론이 있는 이벤트를 생성합니다 .data
. 불행히도 이러한 이벤트를 수신하는 것은 반드시 비동기식이며 동기식 대안은 실용적이지 않습니다.
class StructuredCloner {
constructor() {
this.pendingClones_ = new Map();
this.nextKey_ = 0;
const channel = new MessageChannel();
this.inPort_ = channel.port1;
this.outPort_ = channel.port2;
this.outPort_.onmessage = ({data: {key, value}}) => {
const resolve = this.pendingClones_.get(key);
resolve(value);
this.pendingClones_.delete(key);
};
this.outPort_.start();
}
cloneAsync(value) {
return new Promise(resolve => {
const key = this.nextKey_++;
this.pendingClones_.set(key, resolve);
this.inPort_.postMessage({key, value});
});
}
}
const structuredCloneAsync = window.structuredCloneAsync =
StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);
사용 예 :
const main = async () => {
const original = { date: new Date(), number: Math.random() };
original.self = original;
const clone = await structuredCloneAsync(original);
// They're different objects:
console.assert(original !== clone);
console.assert(original.date !== clone.date);
// They're cyclical:
console.assert(original.self === original);
console.assert(clone.self === clone);
// They contain equivalent values:
console.assert(original.number === clone.number);
console.assert(Number(original.date) === Number(clone.date));
console.log("Assertions complete.");
};
main();
동기 해결 방법 : 끔찍합니다! 🤢
구조적 클론을 동 기적으로 생성하기위한 좋은 옵션은 없습니다. 대신 몇 가지 비현실적인 해킹이 있습니다.
history.pushState()
그리고 history.replaceState()
모두 자신의 첫 번째 인수의 구조화 된 클론을 생성하고 해당 값을 할당합니다 history.state
. 이것을 사용하여 다음과 같은 객체의 구조화 된 복제본을 만들 수 있습니다.
const structuredClone = obj => {
const oldState = history.state;
history.replaceState(obj, null);
const clonedObj = history.state;
history.replaceState(oldState, null);
return clonedObj;
};
사용 예 :
'use strict';
const main = () => {
const original = { date: new Date(), number: Math.random() };
original.self = original;
const clone = structuredClone(original);
// They're different objects:
console.assert(original !== clone);
console.assert(original.date !== clone.date);
// They're cyclical:
console.assert(original.self === original);
console.assert(clone.self === clone);
// They contain equivalent values:
console.assert(original.number === clone.number);
console.assert(Number(original.date) === Number(clone.date));
console.log("Assertions complete.");
};
const structuredClone = obj => {
const oldState = history.state;
history.replaceState(obj, null);
const clonedObj = history.state;
history.replaceState(oldState, null);
return clonedObj;
};
main();
동기식이지만 매우 느릴 수 있습니다. 브라우저 기록 조작과 관련된 모든 오버 헤드가 발생합니다. 이 메소드를 반복해서 호출하면 Chrome이 일시적으로 응답하지 않을 수 있습니다.
Notification
생성자는 그와 연관된 데이터의 구조화 된 클론을 생성한다. 또한 사용자에게 브라우저 알림을 표시하려고 시도하지만 알림 권한을 요청하지 않으면 자동으로 실패합니다. 다른 목적으로 권한을 보유한 경우 Google이 생성 한 알림을 즉시 닫습니다.
const structuredClone = obj => {
const n = new Notification('', {data: obj, silent: true});
n.onshow = n.close.bind(n);
return n.data;
};
사용 예 :
'use strict';
const main = () => {
const original = { date: new Date(), number: Math.random() };
original.self = original;
const clone = structuredClone(original);
// They're different objects:
console.assert(original !== clone);
console.assert(original.date !== clone.date);
// They're cyclical:
console.assert(original.self === original);
console.assert(clone.self === clone);
// They contain equivalent values:
console.assert(original.number === clone.number);
console.assert(Number(original.date) === Number(clone.date));
console.log("Assertions complete.");
};
const structuredClone = obj => {
const n = new Notification('', {data: obj, silent: true});
n.close();
return n.data;
};
main();