JavaScript Web Worker 및 비마스터 스레드 작업 시작

브라우저의 JavaScript는 단일 라인으로 설계되었습니다. 이것은 우리의 모든 JavaScript 코드가 같은 호출 창고를 공유할 것을 의미합니다.언뜻 보니 믿기지 않는 것 같다.우리는 시종 Promises 를 사용하여 병행 조작을 실행한다.그러나 이런 병발성(및setTimeout,setInterval과 기타)은 사용으로 실현되었다.
일반적으로 이것은 충분하다. 특히 주로 데이터를 얻고 표시하거나 입력을 받아들여 HTTP와 서버의 지속적인 데이터를 사용하는 응용 프로그램에 충분하다.그러나 클라이언트 응용 프로그램이 계속 복잡해지고'유사 응용 프로그램'이 되면서 우리는 브라우저에서 점점 더 많은 JavaScript를 실행하는 경향이 있다. 이것은 우리의 단일 스레드(또는'메인 스레드') 에 압력을 준다.다행히도, 우리는 백엔드 라인에서 자바스크립트 코드를 실행함으로써 주 라인의 부담을 줄일 수 있다Web Workers.

무엇이 인터넷 종사자입니까?


DN에 따르면 Web Workers 웹 내용이 백그라운드 라인에서 스크립트를 실행하는 간단한 방법입니다.그것들을 서비스 직원과 혼동하지 마라. 후자는 대리 응용 프로그램의 네트워크 요청을 책임진다.Web Worker의 가치는 여러 JavaScript 실행 컨텍스트를 동시에 실행할 수 있도록 병렬성을 지원하는 것입니다.
Web Worker를 사용할 때 몇 가지 중요한 제한을 고려해야 합니다.
  • 웹 작업자는 완전히 독립된 JavaScript 환경에서 실행되며 주 스레드와 메모리를 공유하지 않고 메시지와 통신
  • worker의 전역 범위는 주 JS 라인과 다르다. window 대상이 없기 때문에 DOM이 없고 localStorage 등이 없다
  • 작업자의 실제 JS 코드는 별도의 파일에 있어야 합니다(이에 대한 자세한 내용은 나중에 참조).
  • 비록 Web Worker의 사용 빈도는 높지 않지만, 이미 오랫동안 존재해 왔으며, 모든 주류 브라우저에서 지원되고 있으며, 심지어 IE 10까지 거슬러 올라갈 수 있다source

    병발과 병렬에 대한 간략한 설명

    Although concurrency and parallelism seem at first to be two terms referring to the same concept, they are different. In short, concurrency is making progress on multiple tasks without doing them in order; think of your application invoking fetch multiple times and performing some task after each Promise resolves, but not necessarily in order and without blocking the rest of your code. Parallelism, however, is doing multiple things at the same time, on multiple CPUs or multiple CPU cores. For more on the topic, check out this awesome StackOverflow post that has several different explanations!


    기본 예


    자, 설명은 충분합니다. 코드를 좀 봅시다!새 인스턴스Worker 를 만들려면 다음과 같이 구조 함수를 사용해야 합니다.
    // main.js
    const worker = new Worker('path/to/worker.js');
    
    위에서 설명한 바와 같이, 이 경로는 마스터 패키지에 있는 별도의 JavaScript 파일을 가리켜야 합니다.따라서 웹 Worker를 처리하기 위해 번들을 구성하거나 체인을 구축해야 할 수도 있습니다.Parcel 를 사용하는 경우 Web Worker는 바로 사용할 수 있습니다!따라서 우리는 이 우편물의 나머지 부분에서 소포를 사용할 것이다.Parcel을 사용하면 다음과 같이 작업자에게 전달되는 실제 소스 코드의 상대 경로를 통해 작업자 인스턴스를 구성할 수 있습니다.
    // main.js
    const worker = new Worker('./worker.js');
    

    NOTE: If you are using Parcel within CodeSandbox, this particular feature isn't currently supported. Instead, you can clone a Parcel boilerplate like this one or make your own, and experiment locally.


    이것은 정말 훌륭하다. 왜냐하면 지금 우리는 우리의 작업 코드에서 NPM 모듈과 ESNext 기능을 사용할 수 있기 때문이다. Parcel은 우리를 위해 단독 패키지를 만드는 임무를 처리할 것이다!🎉
    제외하고는 worker.js 존재하지 않습니다...그것을 만듭니다.다음은 Web Worker의 가장 간단한 예입니다.
    // worker.js
    function handleMessage(event) {
      self.postMessage(`Hello, ${event.data}!`);
    }
    
    self.addEventListener('message', handleMessage);
    
    주의해라, 우리는 여기에서 self 을 사용하지, window 를 사용하지 않는다.이제 메인 스크립트로 돌아가서 메시지를 발표하고 응답을 처리하여 Worker를 테스트합니다.
    // main.js
    const worker = new Worker('./worker.js');
    
    function handleMessage(event) {
      console.log(event.data);
    }
    
    worker.addEventListener('message', handleMessage);
    
    worker.postMessage('Mehdi');
    // Hello, Mehdi!
    
    이게 성공이야!이것은 Web Worker를 사용하는 최소 설정입니다.그러나'hello world'응용 프로그램이 완전히 CPU 집약적인 것은 아니다...보다 구체적인 예를 들어 Web Worker가 언제 유용한지 살펴보겠습니다.

    점프 볼 예


    네트워크 작업자의 유용성을 설명하기 위해 귀속Fibonacci sequence 계산기를 사용합니다. 이 계산기는 다음과 같이 작업 효율이 매우 낮습니다.
    // fib.js
    function fib(position) {
      if (position === 0) return 0;
      if (position === 1) return 1;
      return fib(position - 1) + fib(position - 2);
    }
    
    export default fib;
    
    계산기 중간에서 우리는 신축성 있는 공을 원한다. 이렇게.

    반사 애니메이션은 requestAnimationFrame 순환 중에 발생하는데 이것은 브라우저가 16밀리초마다 공을 그려 보려고 한다는 것을 의미한다.만약 우리의 메인 라인인 자바스크립트가 더 긴 시간을 필요로 한다면, 우리는 프레임과 시각적 jank를 겪게 될 것이다.상호작용과 애니메이션이 가득한 실제 응용 프로그램에서 이 점은 매우 뚜렷하다!위치40에 있는 피보나치 수를 계산해 보자.

    우리의 코드가 실행될 때, 우리의 애니메이션은 최소 1.2초 동안 동결됩니다!어쩐지 귀속 fib 함수는 호출 창고를 지우지 않은 상태에서 총 331160281회가 호출되었다.마찬가지로 이것은 완전히 사용자의 CPU에 달려 있다.이 테스트는 2017년 MacBook Pro에서 진행되었습니다.CPU 스로틀이 6x로 설정된 경우 최대 12초 이상 걸립니다.
    우리는 인터넷 종사자와 함께 그것을 처리합시다.그러나 우리는 응용 프로그램 코드에서 호출과 이벤트 탐지기를 동시에 처리할 필요가 없고 웹 Worker를 중심으로 Promise 기반의 더 좋은 인터페이스를 실현할 필요가 있다.
    우선, Worker를 만듭니다. Worker를 postMessage라고 명명합니다.
    // fib.worker.js
    import fib from './fib';
    
    function handleMessage(event) {
      const result = fib(event);
      self.postMessage(result);
    };
    
    self.addEventListener('message', handleMessage);
    
    이것은 이전 Worker 예시와 마찬가지로 fib.worker.js 함수에 대한 호출만 추가되었습니다.이제 fib 함수를 만듭니다. 이 함수는 최종적으로 위치 파라미터를 받아들여 약속을 되돌려줍니다. 이 약속은 이 위치의 피보나치 수로 해석됩니다.
    // asyncFib.js
    function asyncFib(pos) {
      // We want a function that returns a Promise that resolves to the answer
      return new Promise((resolve, reject) => {
        // Instantiate the worker
        const worker = new Worker('./fib.worker.js');
    
        // ... do the work and eventually resolve
      })
    }
    
    export default asyncFib;
    
    우리는 함수의 반환 값을 얻기 위해 작업자의 정보를 처리해야 한다는 것을 알고 있다. 따라서 asyncFib 이벤트 처리 프로그램을 만들어서 정보를 포착하고 그 안에 포함된 데이터로 우리의 약속을 해석하자.또한 프로세서 내부에서 호출됩니다 fib. 이것은 메모리 유출을 방지하기 위해 Worker 인스턴스를 파괴합니다.
    // asyncFib.js
    function asyncFib(pos) {
      return new Promise((resolve, reject) => {
        const worker = new Worker('./fib.worker.js');
    
        // Create our message event handler
        function handleMessage(e) {
          worker.terminate();
          resolve(e.data);
        }
    
        // Mount message event handler
        worker.addEventListener('message', handleMessage);
      })
    }
    
    우리는 또 message 사건을 처리해야 한다.만약 직원이 실수를 당한다면, 우리는 잘못된 사건을 통해 우리의 약속을 거절하기를 바란다.이것은 우리 임무의 또 다른 퇴장 장면이기 때문에 우리는 여기서 호출하고 싶다worker.terminate():
    // asyncFib.js
    function asyncFib(pos) {
      return new Promise((resolve, reject) => {
        const worker = new Worker('./fib.worker.js');
    
        function handleMessage(e) {
          worker.terminate();
          resolve(e.data);
        }
    
        // Create our error event handler
        function handleError(err) {
          worker.terminate();
          reject(err);
        }
    
        worker.addEventListener('message', handleMessage);
        // Mount our error event listener
        worker.addEventListener('error', handleError);
      })
    }
    
    마지막으로 error 매개 변수의 값 호출worker.terminate()으로 모든 것을 시작합시다!
    // asyncFib.js
    function asyncFib(pos) {
      return new Promise((resolve, reject) => {
        const worker = new Worker('./fib.worker.js');
    
        function handleMessage(e) {
          worker.terminate();
          resolve(e.data);
        }
    
        function handleError(err) {
          worker.terminate();
          reject(err);
        }
    
        worker.addEventListener('message', handleMessage);
        worker.addEventListener('error', handleError);
    
        // Post the message to the worker
        worker.postMessage(pos);
      })
    }
    
    할 수 있을 거예요.남은 마지막 일은 정상적으로 작동하도록 검사하는 것이다.응용 프로그램이 새로운 postMessage 함수를 사용하여 위치pos에 있는 피보나치 수를 계산할 때 어떤 모습인지 보여 줍니다.

    많이 좋아졌어!우리는 이미 주 라인의 막힘을 성공적으로 해제하고 공의 반등을 유지하는 동시에 40 함수를 사용하기 위해 좋은 인터페이스를 만들었다.
    궁금하면 play around with the example app 또는 check out the code on GitHub.

    끝내다


    Web Worker API는 기능이 강력하고 충분히 활용되지 않는 도구로 프런트엔드 개발의 중요한 구성 요소가 될 수 있습니다.오늘날 네트워크 사용자들 사이에서 큰 비율을 차지하는 많은 저급 모바일 장치의 CPU 속도는 비교적 느리지만 여러 개의 코어가 있기 때문에 비주류 구조에서 이익을 얻을 수 있다.나는 인터넷 종사자에 관한 내용과 글쓰기/강연을 공유하는 것을 좋아한다. 만약 네가 흥미가 있다면.
    여기에 또 다른 유용한 자원이 있어 당신의 창의력을 끊임없이 발휘할 수 있습니다.
  • "When should you be using Web Workers?" - Surma
  • Comlink
  • Workerize
  • worker-loader (Webpack loader)
  • 읽어주셔서 감사합니다!

    좋은 웹페이지 즐겨찾기