사용하다보니 seajs의 소스코드에 대해 알게 되었습니다. 다음 질문에 대한 나의 이해는 다음과 같습니다.
1. seajs의 require(XXX) 메소드는 모듈 로딩을 어떻게 구현하나요?
2. 왜 사전 로드가 필요한가요?
3. 빌드 도구가 필요한 이유는 무엇입니까?
4. 빌드 전과 후의 코드 차이점은 무엇이며, 왜 이렇게 하나요?
질문 1: seajs의 require(XXX) 메소드는 모듈 로딩을 어떻게 구현합니까?
코드 로직은 다소 복잡합니다. 소스 코드에 대한 이해는 기사 마지막 부분에 있습니다. 여기서는 모듈 로딩 로직을 간략하게 검토합니다.
1. seajs.use 메소드 항목에서 사용된 모듈 로드를 시작합니다.
2. 이때 사용된 모듈은 모드 캐시에 존재하지 않아야 합니다. seajs는 새로운 모드를 생성하고 초기 상태를 제공합니다.
3. mod.load 메소드 실행
4. 여러 로직을 거친 후 seajs.request 메소드로 이동하여 모듈 파일을 요청합니다. 모듈이 로드된 후 정의 메소드가 실행됩니다.
5. 정의 메소드는 모듈의 종속 모듈을 분석하고 추출하여 저장합니다. 팩토리는 캐시되지만 실행되지는 않습니다.
6. 모듈의 종속 모듈이 다시 로드됩니다. 여전히 종속 모듈이 있으면 로드가 계속됩니다. 모든 종속 모듈이 로드될 때까지.
7. 모든 모듈이 로드된 후 use 메소드의 콜백을 실행합니다.
8. 모듈의 내부 로직은 콜백에서 실행됩니다. require 메소드는 이 프로세스 중에만 실행됩니다.
질문 2: 사전 로드가 필요한 이유는 무엇입니까?
모든 종속 모듈이 로드된 후 seajs.use 메소드가 실제로 콜백을 실행하는 것을 볼 수 있습니다. 비즈니스 로직 코드가 실행되기 전에 모든 종속 모듈 코드가 미리 로드되어야 함을 이해할 수 있습니다. 그렇다면 먼저 미리 로드해야 하는 논리가 있는 이유는 무엇입니까?
답은 논리 코드에서 다른 모듈 메서드를 참조하는 require 메서드의 실행 방법에 있습니다.
var mod = require(id);
이 구문은 모드 획득이 동기 실행 프로세스임을 결정합니다. 모듈 코드가 이전에 사전 로드되지 않은 경우 비동기 로딩 콜백 메서드를 통해서만 구현할 수 있으며 전체 seajs 실행 로직이 완전히 완료됩니다. 다른 것. 비동기성으로 인해 모듈의 실행 순서를 이해하지 못하고 로직을 제어하기 어려워집니다.
질문 3: 빌드 도구가 왜 필요한가요?
빌드하기 전에 각 종속 모듈이 별도로 로드되는 것을 볼 수 있습니다. 이렇게 하면 너무 많은 모듈 요청이 생성되어 페이지 로딩 성능에 해를 끼칩니다. 빌드 도구는 기본적으로 결합된 모듈 로딩 문제를 해결하도록 설계되었습니다.
질문 4: 빌드 전과 후의 코드 차이점은 무엇이며, 왜 이렇게 합니까?
빌드 도구의 역할은 정확히 무엇입니까? 본질적으로 코드 병합 로딩 문제를 해결하기 위한 것이라고 하는데, 단순히 여러 모듈 파일을 하나의 파일로 병합하는 것이 무슨 역할을 하는 것일까요?
물론 그렇지 않습니다. 테스트해 보세요. 단순히 여러 모듈 파일을 하나의 파일로 병합하면 이 파일이 정상적으로 실행되지 않는 것을 알 수 있습니다.
이유는 정의 메소드 구현에 있습니다.
Seajs는 모듈을 정의할 때 정의 메소드에 팩토리 매개변수만 전달할 것을 권장합니다. 정의 메소드를 다시 살펴보면, ID(일시적으로 모듈의 URL과 동일)가 전달되지 않으면 getCurrentScript() 메소드를 사용하여 현재 실행 중인 모듈 파일의 URL 경로를 가져온 다음 이 경로가 모듈 자체와 함께 키 값으로 사용됩니다. 여기서 중요한 점은 전체 seajs 내의 모듈 캐싱 메커니즘이 실제로 각 모듈의 URL을 캐시 키로 사용한다는 것입니다. require(id) 메소드는 궁극적으로 url 키 값을 통해 제공됩니다. require(id) 메소드는 궁극적으로 URL 키 값을 사용하여 캐시된Mods에서 해당 모듈을 찾습니다. 이 키 값은 반복될 수 없으며 실수할 수 없습니다. 그렇지 않으면 모듈 간의 해당 관계가 혼란스러워질 것입니다. 여러 개의 모듈 파일 a, b, c를 단순히 대상 파일 x로 병합하면 getCurrentScript()는 x의 경로만 얻을 수 있고 세 모듈의 키 값을 구별할 수 없어 실행이 반드시 진행됩니다. 잘못된.
따라서 여러 모듈 파일을 함께 병합하려면 각 모듈의 URI를 지정해야 합니다. 즉, 정의 메소드는 id 매개변수를 전달해야 합니다. ID가 전달되면 seajs는 ID를 URL로 변환하고 이를 캐시 키로 사용합니다.
id와 Factory만 전달된 경우, 즉, Define(id, Factory)인 경우 deps = undefine이면 정의 메서드는 parsDependency(factory.toString()) 메서드를 실행하여 팩토리의 종속 모듈을 추출합니다. 그런 다음 모듈 경로를 구문 분석하고 각 모듈의 논리를 온라인으로 개별적으로 로드합니다. 이때 결합 로드의 의미는 상실됩니다.
따라서 병합 로딩의 경우 정의 메소드는 id, deps 및 Factory의 세 가지 매개변수를 올바르게 전달해야 올바르게 실행됩니다.
Seajs의 소위 CMD 모듈 정의 방법은 모든 사람이 모듈 작성 단계에서 하나의 매개변수인 팩토리만 전달하도록 권장하고 나머지 두 개의 매개변수는 이후 코드 구성 단계에서 생성됩니다. 위 내용은 구축 후에 이 두 매개변수가 필요한 이유를 설명합니다.
모듈을 정의할 때 팩토리만 전달하는 것을 옹호하는 이유는 주로 수동으로 전달된 id 및 deps 매개변수가 오류가 발생하기 쉽고 유지 관리가 불편하기 때문이라고 생각합니다. 도구는 효율성을 향상시키고 올바른 매개변수를 보장할 수 있습니다.
별첨: seajs의 주요 코드 로직에 대한 이해.
참고: 소스 코드 버전은 Sea.js 2.3.0
1. 먼저 정의 메소드가 수행하는 작업을 살펴보겠습니다
Module.define = 함수(id, deps, 공장)
정의 메소드는 세 가지 매개변수를 지원합니다. 그 중 id와 deps는 선택사항입니다. 공장이 필요합니다. 코드는 다음 논리에 의해 제어됩니다.
하지만 seajs는 각 모듈이 어떤 모듈에 의존하는지 알아야 하기 때문에 deps가 실제로 필요합니다. 그렇지 않으면 로드할 수 없습니다.
따라서 팩토리가 함수이고 deps가 적극적으로 전달되지 않는 경우 parsDependency 메서드를 사용하여 팩토리의 종속 모듈을 분석해야 합니다.
parseDependency 메서드가 수행하는 주요 작업은 정규식을 사용하여 함수 본문의 모든 require(XXX)에서 XXX를 추출하는 것입니다. 이는 이 함수가 의존하는 모든 모듈입니다.
방법 자체는 복잡하지 않지만 이 정규식은 간단하지 않습니다.
deps를 분석한 후 모듈 정의를 캐시에 저장합니다.
정의 메소드는 모듈을 분석하고 모듈을 저장하기만 하고 모듈을 실행하지는 않는다는 점에 유의하세요.
2. 실제 모듈 실행은 require 메소드에서 이루어집니다. 다음에는 require를 살펴보겠습니다.
간단히 말하면 require 메소드는 id를 기준으로 정의 정의가 저장된 모듈 캐시에서 해당 모듈을 찾아 실행하여 모듈 정의가 반환하는 메소드를 얻는 것입니다.
이 큰 단계 전체에는 자세히 설명해야 할 매우 중요한 단계가 있습니다.
Module.get(require.resolve(id)).
모듈이 필요한 경우 먼저 모듈을 찾아야 합니다. Module.get 메소드가 이 역할을 합니다.
cachedMod가 없으면 새 모듈을 생성하고 이를 cashedMod에 캐시합니다.
define과 rquire 메소드는 복잡해 보이지 않습니다. seajs를 사용하는 주된 이유는 모듈 로딩 로직이 약간 복잡하기 때문입니다.
3. seajs 실행의 실제 진입점은 사용 방법입니다.
use 메소드를 통해 여기의 ID부터 모듈의 로딩 및 실행이 시작됩니다.
로드의 핵심은 mod.load 메소드에 있다고 볼 수 있습니다.
로드 메서드의 코드가 약간 깁니다. 주요 로직은 모드의 현재 상태가 로드되었는지 로드 중인지 확인하는 것입니다.
모듈의 Comfort 함수를 보면 status의 기본값이 0인 것을 알 수 있습니다.
따라서 로드되지 않은 새 모듈은 여기에 있습니다: mod.status = STATUS.LOADING 상태는 로드 중으로 설정되고 후속 로드 로직이 실행됩니다.
다음 단계는 모듈의 종속성 URL을 얻는 것입니다
mod.resolve 방법:
Module.resolve 메서드는 기본적으로 상대 경로, 구성된 경로, 별칭 등을 절대 경로로 변환합니다. 더 이상 코드가 게시되지 않습니다.
모듈 로딩 상태를 업데이트하세요.
모듈 로드 논리:
주로 m.fetch 메소드이며, 여기에 포함된 다른 로직은 여기서 건너뜁니다.
seajs.request가 결국 모듈 파일을 로드하는 것을 볼 수 있습니다.
모든 종속 모듈이 로드된 후 모드의 onload 메소드를 실행합니다
mod.onload() 메소드는 다음과 같습니다
이제 seajs의 핵심 로직을 거의 살펴보셨습니다. 참고로, 이해가 불분명하거나 부정확한 표현이 있는 경우, 자유롭게 함께 논의해 주시기 바랍니다.
위 내용은 이 글의 전체 내용입니다. 모두 마음에 드셨으면 좋겠습니다.