La promessa mai risolta causa perdite di memoria?


91

Ho un Promise. L'ho creato per annullare una richiesta AJAX, se necessario. Ma poiché non ho bisogno di annullare quell'AJAX, non l'ho mai risolto e AJAX è stato completato con successo.

Uno snippet semplificato:

var defer = $q.defer();
$http({url: 'example.com/some/api', timeout: defer.promise}).success(function(data) {
    // do something
});

// Never defer.resolve() because I don't need to cancel that ajax. What happens to this promise after request?

Promesse del genere non risolte mai causano perdite di memoria? Hai qualche consiglio su come gestire il Promiseciclo di vita?


4
Una promessa "mai risolta" può ancora essere "rifiutata". La parola che stavi cercando era "insoddisfatto".
Steven Vachon

$ http è un esempio interessante perché alla fine una richiesta HTTP andrà in timeout (o altrimenti produrrà una risposta di errore), se il client non può raggiungere il server, indipendentemente dalla promessa passata all'argomento 'timeout'.
ryanwebjackson

Risposte:


144

Bene, presumo che tu non mantenga un riferimento esplicito ad esso poiché ciò costringerebbe a rimanere assegnato.

Il test più semplice a cui potrei pensare è in realtà allocare molte promesse e non risolverle:

var $q = angular.injector(["ng"]).get("$q");
setInterval(function () {
    for (var i = 0; i < 100; i++) {
        var $d = $q.defer();
        $d.promise;
    }
}, 10);

E poi guardando il mucchio stesso. Come possiamo vedere negli strumenti di profilazione di Chrome, questo accumula la memoria necessaria per allocare 100 promesse e quindi "rimane lì" a meno di 15 megabyes per l'intera pagina JSFIddle

inserisci qui la descrizione dell'immagine

Dall'altro lato, se guardiamo il $qcodice sorgente

Possiamo vedere che non c'è alcun riferimento da un punto globale a una particolare promessa, ma solo da una promessa ai suoi richiami. Il codice è molto leggibile e chiaro. Vediamo cosa succede se hai comunque un riferimento dalla richiamata alla promessa.

var $q = angular.injector(["ng"]).get("$q");
console.log($q);
setInterval(function () {
    for (var i = 0; i < 10; i++) {
        var $d = $q.defer();
        (function ($d) { // loop closure thing
            $d.promise.then(function () {
                console.log($d);
            });
        })($d);
    }
}, 10);

inserisci qui la descrizione dell'immagine

Quindi, dopo l'assegnazione iniziale, sembra che sia in grado di gestire anche quello :)

Possiamo anche vedere alcuni modelli interessanti di GC se lasciamo che il suo ultimo esempio continui per qualche minuto in più. Possiamo vedere che ci vuole un po ', ma è in grado di pulire i callback.

inserisci qui la descrizione dell'immagine

In breve, almeno nei browser moderni, non devi preoccuparti di promesse irrisolte fintanto che non hai riferimenti esterni ad esse


7
Questo non significherebbe che se una promessa impiega troppo tempo per essere risolta (ma alla fine si risolverà), è a rischio di essere GC?
w

5
@ w.brian a meno che non lo si assegni da qualche parte, ad esempio a una variabile, var b = $http.get(...)o si aggiunga un callback. Anche questo ha un riferimento ad esso. Se qualcosa lo risolve (come hai detto tu - troppo tempo per risolvere significa comunque risolvere) - deve avere un riferimento ad esso. Quindi sì - non sarà GC'd
Benjamin Gruenbaum

3
Gotcha, è quello che pensavo. Quindi, la domanda è "Le promesse non risolte causano perdite di memoria?" La risposta, per il caso d'uso comune in cui viene passato un callback alla promessa, è sì. Questa riga nella tua risposta sembra contraddire che: "Possiamo anche vedere alcuni modelli interessanti di GC se lasciamo che il suo ultimo esempio venga eseguito per qualche minuto in più. Possiamo vedere che ci vuole un po ', ma è in grado di pulire i callback. " Scusa se sono pedante e pignolo, sto solo cercando di assicurarmi di capirlo.
w

1
Non sembra avere senso per me. Se avessi creato 100.000 promesse, console.log () avrebbe scritto qualche riga. Vorrei che quei 100.000 registrassero quelle righe se improvvisamente si risolvessero per magia. O stai dicendo che il browser saprà che questo non si risolverà mai , dal momento che né io né il browser effettivo abbiamo alcun riferimento ad esso (nulla influisce su di esso), quindi come potrebbe mai essere vero? (hmm, posso vedere che potrebbe essere vero)
odinho - Velmont

8
C'è del vero in questi commenti e in altri fuorvianti, quindi lasciatemi chiarire: una promessa con gestori allegati potrebbe essere idonea per la raccolta dei rifiuti. Una promessa viene mantenuta in vita (non idonea per GC) se una delle seguenti condizioni è vera: (1) c'è un riferimento all'oggetto della promessa, (2) c'è un riferimento allo stato "differito" della promessa (l'oggetto / funzioni che usi per risolverlo / rifiutarlo). Al di fuori di questo, la promessa è idonea per GC. (Se nessuno ha la promessa e nessuno può cambiare il suo stato, qual è più il suo scopo, comunque?)
cdhowie
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.