중단 신호: JavaScript에서 비동기 작업을 취소하는 방법

비동기 작업을 수행하는 것은 매우 어려울 수 있습니다. 특히 특정 프로그래밍 언어가 잘못된 시작을 취소하거나 더 이상 필요하지 않을 때입니다.다행히도 JavaScript는 비동기 활동을 중단하는 데 매우 편리한 기능을 제공합니다.본문에서, 중지 가능한 함수를 만드는 방법을 배울 수 있습니다.

중지 신호Promise를 ES2015에 도입한 지 얼마 되지 않아 need to cancel asynchronous tasks emerged가 등장했고 새로운 비동기식 솔루션을 지원하는 웹 API도 몇 개 등장했다.첫 번째 시도의 중점은 creating a universal solution인데 나중에 ECMAScript 표준의 일부가 될 수 있다는 것이다.그러나 토론은 곧 정체되어 문제를 해결할 수 없었다.이에 따라 WHATWG는 자체 솔루션과introduced it directly into the DOM in the form of AbortController 를 준비했습니다.이 솔루션의 뚜렷한 단점은 AbortController 노드에서 사용할 수 없다는 것이다.js, 이 환경에서 다른 작업을 취소하는 우아하거나 공식적인 방법이 없습니다.
DOM 규범에서 보듯이 AbortController에 대한 설명은 매우 무분별합니다.이 때문에 비동기식 API 유형에는 존재하지 않는 API라도 사용할 수 있습니다.현재 Fetch API만 정식으로 지원하지만, 코드에서 사용할 수 있는 것은 아무것도 없습니다!
그러나 시작하기 전에 AbortController의 작업 원리를 분석하는 데 시간이 좀 걸립니다.
const abortController = new AbortController(); // 1
const abortSignal = abortController.signal; // 2

fetch( 'http://example.com', {
  signal: abortSignal // 3
} ).catch( ( { message } ) => { // 5
  console.log( message );
} );

abortController.abort(); // 4
위의 코드를 보십시오. 시작할 때 AbortController DOM 인터페이스 (1) 의 새로운 실례를 만들고 signal 속성을 변수에 연결합니다. (2)그리고 fetch()를 호출하여 전달signal을 옵션 중의 하나로 삼았다(3).자원 취득을 중지하려면 abortController.abort()(4)만 호출하면 됩니다.그것은 자동으로 fetch()의 약속을 거절하고 제어권을 catch() 블록(5)에 전달할 것이다.signal 부동산 자체가 재미있어요. 이 드라마의 주인공이에요.이 속성은 AbortSignal DOM interface의 실례로 이 실례는 aborted 속성이 있는데 사용자가 호출했는지abortController.abort() 방법에 대한 정보를 포함한다.abort 이벤트 탐지기를 호출abortController.abort()에 연결할 때 호출되는 이벤트 탐지기도 사용할 수 있다.다시 말하면 AbortControllerAbortSignal의 공공 인터페이스일 뿐이다.

중단 가능 함수
아주 복잡한 계산을 수행하는 비동기 함수가 있다고 상상해 봅시다. (예: it asynchronously processes data from a big array간단하게 보기 위해 Sample 함수는 결과를 되돌리기 전에 5초를 기다려 힘든 작업을 시뮬레이션합니다.
function calculate() {
  return new Promise( ( resolve, reject ) => {
    setTimeout( ()=> {
      resolve( 1 );
    }, 5000 );
  } );
}

calculate().then( ( result ) => {
  console.log( result );
} );
그러나 때때로 사용자는 이런 대가가 높은 조작을 중지하려고 할 수도 있다.그들은 반드시 이런 능력을 가지고 있어야 한다.계산을 시작하고 중지하는 버튼을 추가합니다.
<button id="calculate">Calculate</button>

<script type="module">
  document.querySelector( '#calculate' ).addEventListener( 'click', async ( { target } ) => { // 1
    target.innerText = 'Stop calculation';

    const result = await calculate(); // 2

    alert( result ); // 3

    target.innerText = 'Calculate';
  } );

  function calculate() {
    return new Promise( ( resolve, reject ) => {
      setTimeout( ()=> {
        resolve( 1 );
      }, 5000 );
    } );
  }
</script>
위 코드에 단추 (1) 에 비동기 click 이벤트 탐지기를 추가하고 그 중 calculate() 함수 (2) 를 호출합니다.결과가 표시되는 경고 대화 상자가 5초 후에 나타납니다(3).또한 script[type=module]는 자바스크립트 코드가 'use strict'pragma보다 우아하기 때문에 엄격한 모드에 들어가도록 강제하는 데 사용된다.
비동기식 작업을 중단하는 기능이 추가되었습니다.
{ // 1
  let abortController = null; // 2

  document.querySelector( '#calculate' ).addEventListener( 'click', async ( { target } ) => {
    if ( abortController ) {
      abortController.abort(); // 5

      abortController = null;
      target.innerText = 'Calculate';

      return;
    }

    abortController = new AbortController(); // 3
    target.innerText = 'Stop calculation';

    try {
      const result = await calculate( abortController.signal ); // 4

      alert( result );
    } catch {
      alert( 'WHY DID YOU DO THAT?!' ); // 9
    } finally { // 10
      abortController = null;
      target.innerText = 'Calculate';
    }
  } );

  function calculate( abortSignal ) {
    return new Promise( ( resolve, reject ) => {
      const timeout = setTimeout( ()=> {
        resolve( 1 );
      }, 5000 );

      abortSignal.addEventListener( 'abort', () => { // 6
        const error = new DOMException( 'Calculation aborted by the user', 'AbortError' );

        clearTimeout( timeout ); // 7
        reject( error ); // 8
      } );
    } );
  }
}
보시다시피 코드가 더 길어졌어요.하지만 당황할 이유가 없다. 이해하기가 더 어려워지지 않았다!
모든 물건이 블록 (1) 안에 갇혀 있는데, 이것은 equivalent of IIFE 이다.이 점 때문에 abortController 변수 (2) 는 전체 범위에 누설되지 않을 것이다.
우선 값을 null로 설정합니다.이 값은 마우스로 단추를 눌렀을 때 변경됩니다.그런 다음 값을 AbortController(3)의 새 인스턴스로 설정합니다.그리고 실례의signal 속성을 calculate() 함수(4)에 직접 전달한다.
사용자가 5초 전에 이 단추를 다시 누르면 abortController.abort() 기능이 호출됩니다(5).이것은 반대로 당신의 앞에서 전달한 abort(6)의AbortSignal 실례에 대한 촉발calculate() 사건입니다.abort 이벤트 탐지기에서 타이머(7)를 제거하고 적당한 오류(8)로 약속을 거부한다. according to the specification 타이머는 DOMException 유형이어야 한다'AbortError'.오류는 결국 제어catch(9)와 finally 블록(10)에 전달됩니다.
또한 코드를 준비하여 이러한 상황을 처리해야 합니다.
const abortController = new AbortController();

abortController.abort();
calculate( abortController.signal );
이 경우 abort 이벤트는 신호를 calculate() 함수에 전달하기 전에 발생하지 않습니다.따라서 다음과 같은 몇 가지 재구성을 수행해야 합니다.
function calculate( abortSignal ) {
  return new Promise( ( resolve, reject ) => {
    const error = new DOMException( 'Calculation aborted by the user', 'AbortError' ); // 1

    if ( abortSignal.aborted ) { // 2
      return reject( error );
    }

    const timeout = setTimeout( ()=> {
      resolve( 1 );
    }, 5000 );

    abortSignal.addEventListener( 'abort', () => {
      clearTimeout( timeout );
      reject( error );
    } );
  } );
}
오류가 맨 위로 이동했습니다(1).이 점 덕분에 코드의 두 가지 다른 부분에서 다시 사용할 수 있습니다. (그러나 아무리 어리석게 들리더라도 오류 공장을 만드는 것이 더 우아할 것입니다.)이 밖에 검사abortSignal.aborted(2)에 사용되는 보호 자구가 나타났다.만약 그것이 true와 같다면 calculate() 함수는 더 이상의 조작을 하지 않고 적당한 오류로 약속을 거부할 것이다.
이것은 완전히 중지할 수 있는 비동기 함수를 만드는 방법입니다.전화번호demo is available online.즐겨라!
본문은 최초로 발표되었다ckeditor.com

좋은 웹페이지 즐겨찾기