귀속할 필요가 없을 수도 있습니다
14516 단어 recursionjavascriptwebdev
Maximum call stack size exceeded
반복은 일반적으로 트리 구조를 처리하는 데 사용되며, 때로는 외부의 페이지 나누기 API에서 알 수 없는 수량의 페이지를 가져오는 데 사용된다.본문에서, 나는 당신에게 귀속 함수의 또 다른 선택을 보여 드리겠습니다. 이것은 가독성을 높일 것입니다."원격에서 가져오기"를 예로 들면, 가져오기 시뮬레이션을 사용할 것입니다.나는 이 함수를 상세하게 설명하고 싶지 않지만, 그것의 서명은
fetch
과 같고, nodes
하나, endCursor
와 hasMore
의 결과를 되돌려주며, 우리에게 더 많은 사용 가능한 페이지가 있는지 알려 줍니다.이 아이디어는 hasMore
와 같기만 하면 true
더 많은 페이지를 얻을 수 있다는 것이다.const db = Array.from({ length: 10 }).map((_, idx) => ({ id: idx }));
async function fetch(url, { body } = {}) {
let after = JSON.parse(body || '{}').after;
if (typeof after === 'undefined') {
after = -1;
}
return {
json: async () => {
const nodes = db.slice(after + 1, after + 3);
const lastNode = nodes.slice(-1)[0];
const endCursor = lastNode ? lastNode.id : null;
const hasMore = lastNode ? lastNode.id < db.length - 1 : false;
return { nodes, endCursor, hasMore };
},
};
}
async function fetchPage({ after }) {
return fetch('https://example.com', {
body: JSON.stringify({ after }),
}).then((response) => response.json());
}
그 장면을 그냥 잊어버려도 돼.나는 단지 그것을 공유할 뿐이다. 그러면 내가 사용하고 있는 모든 코드가 생길 것이다. 만약 네가 원한다면, 너는 리플에서 그것을 실행할 수 있다.이전에 API를 사용한 적이 있다면 이 구조가 익숙해 보일 수 있습니다.역귀함수
여기서 귀속 함수의 가장 전통적인 방법을 보실 수 있습니다.먼저 API에서 페이지를 가져옵니다.페이지가 더 이상 없으면
hasMore
결과를 되돌려주고 트리로 돌아갑니다.그렇지 않으면 다시 전화하겠습니다fetchAllNodes
.이것은 현재 실행 중인 기능과 같습니다.이것이 바로 그것이 귀속되는 원인이다.함수 호출 자체.async function fetchAllNodes(after) {
const result = await fetchPage({ after });
if (!result.hasMore) {
return result.nodes;
}
// recursive call
const innerNodes = await fetchAllNodes(result.endCursor);
return [...result.nodes, ...innerNodes];
}
이 함수의return 문장은 되돌아오기 전에 '직접 결과' 와 '끼워넣기 결과' 를 병합합니다.이것은 항상 최종 결과를 직접적으로 초래하는 것은 아니므로 주의하십시오.이런 함수는 '나무 위' 로 돌아가기 전에 '나무 아래' 를 먼저 한다.호출 스택은 다른 관점에서 다음과 같습니다.fetchAllNodes(undefined)
# result.nodes = [{ id: 0 }, { id: 1 }]
fetchAllNodes(1)
# result.nodes = [{ id: 2 }, { id: 3 }]
fetchAllNodes(3)
# result.nodes = [{ id: 4 }, { id: 5 }]
fetchAllNodes(5)
# result.nodes = [{ id: 6 }, { id: 7 }]
fetchAllNodes(7)
# result.nodes = [{ id: 8 }, { id: 9 }]
return [{ id: 8 }, { id: 9 }]
# merge results
return [{ id: 6 }, { id: 7 }, { id: 8 }, { id: 9 }]
# merge results
return [{ id: 4 }, { id: 5 }, { id: 6 }, …, …, { id: 9 }]
# merge results
return [{ id: 2 }, { id: 3 }, { id: 4 }, …, …, …, …, { id: 9 }]
# merge results
return [{ id: 0 }, { id: 1 }, { id: 2 }, …, …, …, …, …, …, { id: 9 }]]
이 함수에 대한 다섯 번째 호출은 네 번째 호출 포장, 세 번째 호출 포장, 두 번째 호출 포장, 첫 번째 호출 포장을 보실 수 있습니다.현재, 이것은 요청 체인으로, 다섯 번의 호출에서 완성됩니다.수십 페이지, 심지어 수백 페이지가 있는 원격 장치에서 페이지를 가져올 때 이런 상황이 발생할 것이라고 상상해 보세요.호출 창고가 계속 증가하고 있으며, 이 함수의 모든 변수는 메모리에 저장됩니다.한 페이지의 결과가 아니라 모든 결과다.합병, 그리고 개인.쓰레기 수집은 최종 결과를 되돌려주고 모든 요청이 끝난 후에만 청소할 수 있습니다.
후방 호출 최적화
최적화를 통해 함수를 되돌아오는 문장의 함수로 호출함으로써 끝부분 호출 최적화는 상기 상황에서의 성능 수요를 줄일 수 있어야 한다.
이런 최적화를 이용하기 위해서 우리는 노드 그룹이 아니라 함수 호출을 되돌려야 한다.여전히 결과를 통합할 수 있도록 함수 서명을 조정하고 현재 결과를 매개 변수로 전달해야 합니다.
async function fetchAllNodes(after, nodes = []) {
const result = await fetchPage({ after });
const allNodes = [...nodes, ...result.nodes];
if (!result.hasMore) {
return allNodes;
}
// recursive tail call
return fetchAllNodes(result.endCursor, allNodes);
}
비록 끝부분 호출 최적화는 ECMAScript 규범의 일부이지만, 본문을 작성할 때 Safari는 유일하게 지원하는 브라우저이다.그래서 어떤 스타일을 더 좋아하십니까? 현재는 주로 개인적인 취향입니다.has this implemented
교체했어
내가 제목에서 언급한 것처럼귀속할 필요가 없을 수도 있습니다.위 함수는 더 간단한while 주기로 재작성할 수 있습니다.
async function fetchAllNodes() {
const nodes = [];
let after;
while (after !== null) {
const result = await fetchPage({ after });
nodes.push(...result.nodes);
after = result.endCursor;
}
return nodes;
}
네가 그것을 보았을 때, 그것은 이렇게 간단하고 뚜렷하게 보였다.그러나 어떤 문장들은 어떻게 귀속적으로 얻는지 설명할 것이다.모든 프레임과 결과 사이의 내용을 추적할 필요가 없기 때문에, 이전 예시의 메모리 사용량이 감소했다.이것은 단일 프레임의 단일 함수 호출입니다.더 복잡한 장면을 만났을 때 오류 처리, 스케줄링, 재시도 등 내용을 추가하고, 심지어 병행 작업을 하는 직원을 추가하는 것도 더욱 쉽다.
하지만 더 중요한 것은;순환은 읽기와 이해가 더욱 쉽다.
👋 스티븐입니다. 짓고 있습니다. 제 작품을 더 많이 읽고 싶으시면 따라오시거나 rake.red로 전화해서 제 작품을 보세요.
Reference
이 문제에 관하여(귀속할 필요가 없을 수도 있습니다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/smeijer/you-might-not-need-recursion-282b텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)