Maison > Article > interface Web > Comment annuler une tâche asynchrone en JavaScript ?
Parfois, il peut être difficile d'effectuer des tâches asynchrones, surtout lorsqu'un langage de programmation particulier ne permet pas l'annulation d'opérations lancées par erreur ou qui ne sont plus nécessaires. Heureusement, JavaScript fournit une fonctionnalité très pratique pour abandonner les activités asynchrones. Dans cet article, vous pouvez apprendre à créer des fonctions avortables.
Signal d'abandon
Après l'introduction de Promise
dans ES2015 et l'émergence de certaines API Web supportant de nouvelles solutions asynchrones Bientôt, la nécessité d'annuler les tâches asynchrones est apparue. Les premières tentatives se concentrent sur la création d'une solution universelle dans l'espoir de faire partie du standard ECMAScript à l'avenir. Cependant, la discussion s’est rapidement retrouvée dans une impasse et n’a pas réussi à résoudre le problème. Par conséquent, le WHATWG a préparé sa propre solution et l'a introduite directement dans le DOM AbortController
sous la forme de . L'inconvénient évident de cette solution est que AbortController
n'est pas disponible dans Node.js, il n'existe donc aucun moyen élégant ou officiel d'annuler une tâche asynchrone dans cet environnement.
Comme vous pouvez le voir dans la spécification DOM, AbortController
est décrit de manière très générale. Vous pouvez donc l'utiliser dans n'importe quel type d'API asynchrone, même celles qui n'existent pas encore. Actuellement, seule l'API Fetch est officiellement prise en charge, mais vous pouvez également l'utiliser dans votre propre code !
Avant de commencer, prenons un moment pour analyser le fonctionnement de 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
Regardez le code ci-dessus et vous le verrez on constate qu'une nouvelle instance de l'interface AbortController
DOM est créée au début (1) et ses propriétés signal
sont liées à des variables (2). Appelez ensuite fetch()
passant signal
comme l'une de ses options (3). Pour abandonner la récupération d'une ressource, vous appelez simplement abortController.abort()
(4). Il rejettera automatiquement la promesse de fetch()
et le contrôle sera transmis au bloc catch()
(5).
signal
La propriété elle-même est très intéressante et c'est la star principale du spectacle. Cette propriété est une instance de l'interface AbortSignal
DOM qui possède un attribut aborted
contenant des informations indiquant si l'utilisateur a appelé la méthode abortController.abort()
. Vous pouvez également lier l'écouteur d'événement abort
à l'écouteur d'événement qui sera appelé lorsque abortController.abort()
est appelé. En d'autres termes : AbortController
n'est que l'interface publique de AbortSignal
. 3bb3ba5d8a8c1e677360c9d603cb067b données
function calculate() { return new Promise( ( resolve, reject ) => { setTimeout( ()=> { resolve( 1 ); }, 5000 ); } ); } calculate().then( ( result ) => { console.log( result ); } );Mais parfois les utilisateurs souhaitent pouvoir abandonner cette pénalité, opération coûteuse. Oui, ils devraient avoir cette capacité. Ajoutez un bouton pour démarrer et arrêter le calcul :
<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)。五秒钟后,将显示带有结果的警报对话框(3)。另外, script [type = module]
用于强制 JavaScript 代码进入严格模式——因为它比 'use strict'
编译指示更为优雅。
现在添加中止异步任务的功能:
{ // 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)中,该块相当于IIFE。因此,abortController
变量(2)不会泄漏到全局作用域内。
首先,将其值设置为 null
。鼠标单击按钮时,此值会更改。然后将其值设置为 AbortController
的新实例(3)。之后,将实例的 signal
属性直接传递给你的 calculate()
函数(4)。
如果用户在五秒钟之内再次单击该按钮,则将导致调用 abortController.abort()
函数(5)。反过来,这将在你先前传递给 calculate()
的 AbortSignal
实例上触发 abort
事件(6)。
在 abort
事件侦听器内部,删除了滴答计时器(7)并拒绝了带有适当错误的promise (8; 根据规范 ,它必须是类型为 'AbortError'
的 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( '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()
函数将会拒绝带有适当错误的 promise,而无需执行任何其他操作。
这就是创建完全可中止的异步函数的方式。 演示可在这里获得(https://blog.comandeer.pl/ass...)。请享用!
英文原文地址:https://ckeditor.com/blog/Aborting-a-signal-how-to-cancel-an-asynchronous-task-in-JavaScript/
相关教程推荐:JavaScript视频教程
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!