Electron Adventures: 에피소드 84: 고성능 16진수 편집기
14070 단어 electronsveltejavascript
그럼 우리가 에피소드 69에서 했던 것부터 시작해서 정말 빠르게 만들어 봅시다.
성능 문제
Hex Editor의 성능 스토리는 두 부분으로 나뉩니다.
처음에는 앱이 모든 행에 대해 DOM을 생성했기 때문에 시작 속도가 매우 느렸지만 이후에는 업데이트가 더 이상 필요하지 않아 매우 순조로웠습니다.
변경 후 앱은 모든 행에 대해 빈 자리 표시자 DOM 항목을 만든 다음 스크롤이 발생할 때마다 데이터를 표시하는 데 필요한 행(화면)과 비어 있을 수 있는 행(화면 외부)을 확인했습니다. 초기 렌더링은 훨씬 빨랐지만 여전히 놀랍지는 않았습니다. 이제 Svelte가 업데이트에 필요한 앱을 파악해야 했기 때문에 스크롤 속도가 느렸습니다.
새로운 솔루션
음, 그런데 왜 자리 표시자 요소를 만드는 데 신경을 써야 할까요? 그래서 여기에 새로운 아이디어가 있습니다. 모든 요소에 맞게 컨테이너 크기를 늘린 다음 필요한 요소만 만듭니다. 구현을 단순화하기 위해 모든 행의 높이를 16px로 설정했습니다.
src/Slice.svelte
<script>
import { printf } from "fast-printf"
import AsciiSlice from "./AsciiSlice.svelte"
export let offset
export let rowNumber
export let data
</script>
<div class="row" style={`top: ${16*rowNumber}px`} class:even={rowNumber % 2}>
<span class="offset">{printf("%06d", offset)}</span>
<span class="hex">
{#each {length: 16} as _, i}
<span data-offset={offset + i}>
{data[i] !== undefined ? printf("%02x", data[i]) : " "}
</span>
{/each}
</span>
<AsciiSlice {data} />
</div>
<style>
.row {
position: absolute;
width: 100%;
height: 16px;
}
.even {
background-color: #555;
}
.offset {
margin-right: 0.75em;
}
.hex span:nth-child(4n) {
margin-right: 0.75em;
}
</style>
몇 가지만 변경하면 되었습니다.
if visible
논리rowNumber
(지금은 항상 offset/16
이지만 둘 다 전달하는 것이 더 논리적으로 보입니다)rowNumber
에 따라 배치됩니다.even
/odd
논리를 수행하기 위해 CSS에 의존할 수 없습니다. 처음 실제로 보이는 요소가 홀수인지 짝수인지 알 수 없기 때문에 .even
클래스를 직접 관리해야 합니다src/MainView.svelte
<script>
import Slice from "./Slice.svelte"
import { createEventDispatcher } from "svelte"
export let data
let dispatch = createEventDispatcher()
let slices
let main1
let main2
let firstVisible = 0
let lastVisible = 200
$: {
slices = []
for (let i=0; i<data.length; i+=16) {
slices.push({
rowNumber: i/16,
offset: i,
data: data.slice(i, i+16),
})
}
}
$: visibleSlices = slices.slice(firstVisible, lastVisible+1)
$: totalHeight = `height: ${16*slices.length}px`
function onmouseover(e) {
if (!e.target.dataset.offset) {
return
}
dispatch("changeoffset", e.target.dataset.offset)
}
function setVisible() {
let rowHeight = 16
firstVisible = Math.floor(main1.scrollTop / rowHeight)
lastVisible = Math.ceil((main1.scrollTop + main1.clientHeight) / rowHeight)
main2.focus()
}
function init1(node) {
main1 = node
setVisible()
}
function init2(node) {
main2 = node
}
</script>
<div
class="main1"
on:scroll={setVisible}
use:init1
>
<div
class="main2"
on:mouseover={onmouseover}
style={totalHeight}
use:init2
tabindex="-1"
>
{#each visibleSlices as slice (slice.offset)}
<Slice {...slice} />
{/each}
</div>
</div>
<svelte:window on:resize={setVisible} />
<style>
.main1 {
flex: 1 1 auto;
overflow-y: auto;
width: 100%;
}
.main2 {
position: relative;
}
</style>
아마도 가장 깔끔한 코드는 아닐 것입니다. 외부
main1
스크롤 가능 뷰포트 div(사용 가능한 공간에 맞게 크기가 조정됨)와 내부main2
div 크기가 모든 행에 맞도록 조정되었습니다.여기에 몇 가지 트릭이 있습니다. 내부
tabindex="-1"
에 main2
를 추가하고 스크롤할 때마다 계속 실행main2.focus()
해야 합니다. 그렇지 않으면 키보드 탐색이 작동하지 않습니다. 이전 버전에서 초점이 맞춰진 것은 개별 행이었지만 이제는 삭제하므로 초점을 main2
로 이동하는 대신 완전히 제거합니다. 초점을 강제로 유지하면main2
키보드 탐색이 작동합니다. 이것은 가장 우아한 솔루션은 아니지만 선택할 수 있는 다른 것이 없으므로 작동합니다. 더 복잡한 앱에서는 삭제될 행에 속한 경우에만 포커스를 훔쳐야 합니다.{#each visibleSlices as slice (slice.offset)}
로 반복할 때 루프 인덱스 대신 slice.offset
로 행을 식별하도록 Svelte에 지시해야 합니다. 그렇지 않으면 AsciiSlice
구성 요소가 지금처럼 생성 시에만 데이터를 계산하는 대신 매번 데이터를 다시 계산하도록 지시해야 합니다.물론
main2
구성 요소 중 position: relative
가 기본 창이 아니라 position: absolute
를 기반으로 한다는 것을 브라우저에 알리려면 Slice
를 main2
로 태그 지정해야 합니다.결과
결과는 다음과 같습니다.
다음 에피소드에서 우리는 몇 가지 게임을 작성합니다.
평소와 같이 all the code for the episode is here .
Reference
이 문제에 관하여(Electron Adventures: 에피소드 84: 고성능 16진수 편집기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/taw/electron-adventures-episode-84-high-performance-hex-editor-4pf2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)