> 웹 프론트엔드 > JS 튜토리얼 > JavaScript에서 비동기 작업을 취소하는 방법은 무엇입니까?

JavaScript에서 비동기 작업을 취소하는 방법은 무엇입니까?

青灯夜游
풀어 주다: 2020-07-06 10:08:26
앞으로
2982명이 탐색했습니다.

JavaScript에서 비동기 작업을 취소하는 방법은 무엇입니까?

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

Abort 신호

ES2015에 Promise가 도입되고 새로운 비동기 솔루션을 지원하기 위해 일부 웹 API가 등장한 직후 비동기 작업을 취소해야 할 필요성이 나타났습니다Promise 引入 ES2015 并出现了一些支持新异步解决方案的 Web API 之后不久,需要取消异步任务的需求就出现了。最初的尝试集中在创建通用解决方案上,并期待以后可以成为 ECMAScript 标准的一部分。但是,讨论很快陷入僵局,无法解决问题。因此,WHATWG 准备了自己的解决方案,并AbortController 的形式将其直接引入 DOM。这种解决方案的明显缺点是 Node.js 中不提供 AbortController,从而在该环境没有任何优雅或官方的方式来取消异步任务。

正如你在 DOM 规范中所看到的,AbortController 是用一种非常通用的方式描述的。所以你可以在任何类型的异步 API 中使用 —— 甚至是那些目前还不存在的 API。目前只有 Fetch API 正式支持,但是你也可以在自己的代码中使用它!

在开始之前,让我们花点时间分析一下 AbortController. 초기 시도는 ECMAScript 표준 부분이 되기를 희망하면서 범용 솔루션을 만드는

에 중점을 둡니다. . 그러나 논의는 빠르게 교착상태에 빠졌고 문제를 해결하지 못했습니다. 따라서 WHATWG는 AbortController를 사용하여 자체 솔루션을 준비했습니다. 는 이를 DOM

에 직접 소개합니다. 이 솔루션의 명백한 단점은 Node.js에서 AbortController가 제공되지 않으므로 이 환경에서 비동기 작업을 취소하는 우아하거나 공식적인 방법이 없다는 것입니다. DOM 사양에서 볼 수 있듯이 AbortController는 매우 일반적인 방식으로 설명됩니다. 따라서 아직 존재하지 않는 API라도 모든 종류의 비동기 API에서 사용할 수 있습니다. 현재는 Fetch API만 공식적으로 지원되지만, 자신의 코드에서도 사용할 수 있습니다!

시작하기 전에 잠시 AbortController의 작동 방식을 분석해 보겠습니다. AbortController DOM 接口的新实例(1),并将其 signal 属性绑定到变量(2)。然后调用 fetch() 并传递 signal 作为其选项之一(3)。要中止获取资源,你只需调用abortController.abort()(4)。它将自动拒绝 fetch()的 promise,并且控件将传递给 catch()块(5)。

signal 属性本身非常有趣,它是该节目的主要明星。该属性是 AbortSignal DOM 接口的实例,该实例具有 aborted 属性,其中包含有关用户是否已调用 abortController.abort() 方法的信息。你还可以将 abort 事件侦听器绑定到将要调用 abortController.abort() 时调用的事件监听器。换句话说:AbortController 只是 AbortSignal

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<가 생성된 것을 알 수 있습니다. /code> DOM 인터페이스의 새 인스턴스(1)이며 해당 <code>signal 속성을 ​​변수(2)에 바인딩합니다. 그런 다음 fetch()를 호출하고 signal을 옵션 중 하나로 전달합니다(3). 리소스 검색을 중단하려면 abortController.abort()(4)를 호출하기만 하면 됩니다. 자동으로 fetch() 약속을 거부하고 제어권이 catch() 블록(5)으로 전달됩니다.

signal 속성 자체는 꽤 흥미롭고 쇼의 주요 스타입니다. 이 속성은 AbortSignal DOM의 인스턴스입니다. 인터페이스

, 이 인스턴스에는 사용자가 abortController.abort() 메서드를 호출했는지 여부에 대한 정보가 포함된 abort 속성이 있습니다. abortController.abort()가 호출될 때 호출되는 이벤트 리스너에 abort 이벤트 리스너를 바인딩할 수도 있습니다. 즉, AbortControllerAbortSignal의 공개 인터페이스일 뿐입니다.

종료 가능 함수

매우 복잡한 계산을 수행하기 위해 비동기 함수를 사용한다고 가정해 보겠습니다(예:

대규모 배열의 데이터 처리 🎜 비동기식). 단순화를 위해 예제 함수는 결과를 반환하기 전에 5초를 기다려 이를 시뮬레이션합니다. 🎜🎜🎜🎜🎜
function calculate() {
  return new Promise( ( resolve, reject ) => {
    setTimeout( ()=> {
      resolve( 1 );
    }, 5000 );
  } );
}

calculate().then( ( result ) => {
  console.log( result );
} );
로그인 후 복사
🎜 그러나 때때로 사용자는 비용이 많이 드는 이 작업을 중단할 수 있기를 원합니다. 네, 이런 능력이 있어야 합니다. 계산을 시작하고 중지하는 버튼을 추가하세요: 🎜

Calculate" title="" data-original-title="复制">

<button id="calculate">Calculate</button>

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

    const result = await calculate(); // 2

    alert( result ); // 3

    target.innerText = &#39;Calculate&#39;;
  } );

  function calculate() {
    return new Promise( ( resolve, reject ) => {
      setTimeout( ()=> {
        resolve( 1 );
      }, 5000 );
    } );
  }
</script>
로그인 후 복사

在上面的代码中,向按钮(1)添加一个异步 click 事件侦听器,并在其中调用 calculate() 函数(2)。五秒钟后,将显示带有结果的警报对话框(3)。另外, script [type = module] 用于强制 JavaScript 代码进入严格模式——因为它比 &#39;use strict&#39; 编译指示更为优雅。

现在添加中止异步任务的功能:

{ // 1
  let abortController = null; // 2

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

      abortController = null;
      target.innerText = &#39;Calculate&#39;;

      return;
    }

    abortController = new AbortController(); // 3
    target.innerText = &#39;Stop calculation&#39;;

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

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

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

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

        clearTimeout( timeout ); // 7
        reject( error ); // 8
      } );
    } );
  }
}
로그인 후 복사

如你所见,代码变得更长了。但是没有理由惊慌,它并没有变得更难理解!

一切都包含在块(1)中,该块相当于IIFE。因此,abortController 变量(2)不会泄漏到全局作用域内。

首先,将其值设置为 null 。鼠标单击按钮时,此值会更改。然后将其值设置为 AbortController 的新实例(3)。之后,将实例的 signal 属性直接传递给你的 calculate() 函数(4)。

如果用户在五秒钟之内再次单击该按钮,则将导致调用 abortController.abort() 函数(5)。反过来,这将在你先前传递给 calculate()AbortSignal 实例上触发 abort 事件(6)。

abort 事件侦听器内部,删除了滴答计时器(7)并拒绝了带有适当错误的promise (8; 根据规范 ,它必须是类型为 &#39;AbortError&#39;DOMException)。该错误最终把控制权传递给 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( 
    &#39;Calculation aborted by the user&#39;, &#39;AbortError&#39; 
    ); // 1

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

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

    abortSignal.addEventListener( &#39;abort&#39;, () => {
      clearTimeout( timeout );
      reject( error );
    } );
  } );
}
로그인 후 복사

错误被移到顶部(1)。因此,你可以在代码不同部分中重用它(但是,创建一个错误工厂会更优雅,尽管听起来很愚蠢)。另外出现了一个保护子句,检查 abortSignal.aborted(2)的值。如果等于 true,那么 calculate() 函数将会拒绝带有适当错误的 promise,而无需执行任何其他操作。

这就是创建完全可中止的异步函数的方式。 演示可在这里获得(https://blog.comandeer.pl/ass...)。请享用!

英文原文地址:https://ckeditor.com/blog/Aborting-a-signal-how-to-cancel-an-asynchronous-task-in-JavaScript/

相关教程推荐:JavaScript视频教程

위 내용은 JavaScript에서 비동기 작업을 취소하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:segmentfault.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿