Promessa – è ansible forzare annullare una promise

Uso ES6 Promises per gestire tutti i miei dati di rete recuperati e ci sono alcune situazioni in cui ho bisogno di forzarli per cancellarli.

Fondamentalmente lo scenario è tale che ho una ricerca di tipo-ahead sull’interfaccia utente in cui la richiesta è delegata al back-end deve effettuare la ricerca in base all’input parziale. Mentre questa richiesta di rete (n. 1) potrebbe impiegare un po ‘di tempo, l’utente continua a digitare il che alla fine triggers un’altra chiamata di backend (n. 2)

In questo caso # 2 ha la precedenza sul numero 1, quindi vorrei annullare la richiesta # 1 di avvolgimento promise. Ho già una cache di tutte le promesse nel livello dati, quindi posso teoricamente recuperarla mentre sto tentando di inviare una promise per # 2.

Ma come posso annullare Promise # 1 una volta recuperato dalla cache?

Qualcuno potrebbe suggerire un approccio?

No. Non possiamo ancora farlo.

Le promesse ES6 non supportano ancora la cancellazione. Sta arrivando e il suo design è qualcosa a cui molte persone hanno lavorato duramente. La semantica dell’annullamento del suono è difficile da ottenere e questo è in corso. Ci sono interessanti dibattiti sul repository “fetch”, su esdiscuss e su molti altri repository su GH ma sarei solo paziente se fossi in te.

Ma, ma, ma … la cancellazione è davvero importante!

È, la realtà della questione è la cancellazione è davvero uno scenario importante nella programmazione lato client. I casi che descrivi come l’interruzione delle richieste web sono importanti e sono ovunque.

Quindi … il linguaggio mi ha fregato!

Sì, mi dispiace per quello. Le promesse dovevano entrare prima che venissero specificate ulteriori cose – quindi entrarono senza alcune cose utili come .cancel e .cancel – è comunque in arrivo, verso le specifiche attraverso il DOM. L’annullamento non è un ripensamento, è solo un limite di tempo e un approccio più iterativo alla progettazione dell’API.

Quindi cosa posso fare?

Hai diverse alternative:

  • Usa una libreria di terze parti come bluebird che può spostarsi molto più velocemente rispetto alle specifiche e quindi avere una cancellazione oltre a un sacco di altri gadget – questo è ciò che fanno grandi aziende come WhatsApp.
  • Passa un token di cancellazione.

Usare una libreria di terze parti è abbastanza ovvio. Per quanto riguarda un token, puoi triggersre il tuo metodo e quindi chiamarlo, in quanto tale:

 function getWithCancel(url, token) { // the token is for cancellation var xhr = new XMLHttpRequest; xhr.open("GET", url); return new Promise(function(resolve, reject) { xhr.onload = function() { resolve(xhr.responseText); }); token.cancel = function() { // SPECIFY CANCELLATION xhr.abort(); // abort request reject(new Error("Cancelled")); // reject the promise }; xhr.onerror = reject; }); }; 

Quale ti permetterebbe di fare:

 var token = {}; var promise = getWithCancel("/someUrl", token); // later we want to abort the promise: token.cancel(); 

Il tuo caso d’uso reale – last

Questo non è troppo difficile con l’approccio token:

 function last(fn) { var lastToken = { cancel: function(){} }; // start with no op return function() { lastToken.cancel(); var args = Array.prototype.slice.call(arguments); args.push(lastToken); return fn.apply(this, args); }; } 

Quale ti permetterebbe di fare:

 var synced = last(getWithCancel); synced("/url1?q=a"); // this will get canceled synced("/url1?q=ab"); // this will get canceled too synced("/url1?q=abc"); // this will get canceled too synced("/url1?q=abcd").then(function() { // only this will run }); 

E no, le librerie come Bacon e Rx non “brillano” qui perché sono librerie osservabili, hanno solo lo stesso vantaggio che le librerie di promise del livello utente non sono legate alle specifiche. Immagino che aspetteremo di vedere e vedere in ES2016 quando gli osservabili diventano nativi. Sono comunque eleganti per typeahead.

Le proposte standard per le promesse cancellabili sono fallite.

Una promise non è una superficie di controllo per l’azione asincrona che lo soddisfa; confonde il proprietario con il consumatore. Invece, crea funzioni asincrone che possono essere cancellate attraverso un token passato.

Un’altra promise è un bel token, rendendo facile l’annullamento da implementare con Promise.race :

Esempio: utilizza Promise.race per annullare l’effetto di una catena precedente:

 let cancel = () => {}; input.oninput = function(ev) { let term = ev.target.value; console.log(`searching for "${term}"`); cancel(); let p = new Promise(resolve => cancel = resolve); Promise.race([p, getSearchResults(term)]).then(results => { if (results) { console.log(`results for "${term}"`,results); } }); } function getSearchResults(term) { return new Promise(resolve => { let timeout = 100 + Math.floor(Math.random() * 1900); setTimeout(() => resolve([term.toLowerCase(), term.toUpperCase()]), timeout); }); } 
 Search:  

Ho controllato il riferimento a Mozilla JS e ho trovato questo:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race

Controlliamolo:

 var p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, "one"); }); var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "two"); }); Promise.race([p1, p2]).then(function(value) { console.log(value); // "two" // Both resolve, but p2 is faster }); 

Abbiamo qui p1 e p2 inseriti in Promise.race(...) come argomenti, questo in realtà sta creando una nuova promise di risoluzione, che è ciò che ti serve.