2017-03-21 6 views
0

Ich brauche eine Initialisierungsfunktion, die nur einmal für ein Modul aufgerufen wird. Diese Funktion ist ein Versprechen und wird von einer Ausführungsfunktion aufgerufen. Wenn execute zweimal aufgerufen wird, muss der zweite die Initialisierung warten und dann die Ausführung fortsetzen.Wie erstelle ich eine Initialisierungsfunktion mit Versprechen?

Ich habe diesen Code geschrieben, aber der zweite Aufruf von execute wartet immer und kehrt nie zurück. Was habe ich verpasst?

var initialized = false; 
var initializing = false; 
var initializationPromise; 

var init = function() { 
    initializing = true; 
    return q.promise(function (resolve) { 
     // simulate initialization 
     setTimeout(function() { 
      // initialized 
      initialized = true; 
      resolve(); 
     }, 1000); 
    }).fin(function() { 
     initializing = false; 
    }); 
}; 
var execute = function() { 
    return q.promise(function (resolve, reject, notify) { 
     if (initialized) { 
      // already initialized 
      resolve(); 
     } else { 
      if (!initializing) { 
       // initializing 
       initializationPromise = init().then(function() { 
        // simulate execution 
        setTimeout(function() { 
         resolve(); 
        }, 1000); 
       }, function (reason) { 
        reject(reason); 
       }); 
      } else { 
       // Wait : initializing in progress 
       return initializationPromise; 
      } 
     } 

    }); 
}; 

execute().then(function() { 
    // This is executed 
}); 
execute().then(function() { 
    // This is never executed 
}); 
+0

Mit "* Diese Funktion ist ein Versprechen *" Sie bedeuten, "diese Funktion * Returns * ein Versprechen"? – Bergi

Antwort

1
// Wait : initializing in progress 
return initializationPromise; 

ist nicht korrekt. Das wartet nicht auf irgendetwas, es fällt einfach aus dem q.promise Konstruktor und macht nichts. Auch Sie scheinen die Promise constructor antipattern zu beschäftigen.

Was sollten Sie stattdessen tun ist

var initialisationPromise = null; 
function isInitialised() { 
    return initialisationPromise != null && initialisationPromise.isFulfilled(); 
} 
function isInitialising() { 
    return initialisationPromise != null && initialisationPromise.isPending(); 
} 

function init() { 
    // init can be called as often as necessary, and returns when it's done 
    if (initialisationPromise == null) { // do the test here! 
     // this part runs only once 
     initialisationPromise = q.promise(function (resolve) { 
      // simulate initialization 
      setTimeout(function() { 
       // initialized 
       resolve(); 
      }, 1000); 
     }); 
    } 
    return initialisationPromise; 
} 
function execute() { 
    return init().then(function() { 
     return q.promise(function(resolve, reject, notify) { 
      // simulate execution 
      setTimeout(function() { 
       resolve(); 
      }, 1000); 
     }); 
    }); 
} 
0

A aufgelöst/abgelehnt Versprechen wird seinen Zustand (gelöst oder abgelehnt Zustand) gehalten werden, so dass Sie es verwenden können, nur einmal die Initialisierung Code auszuführen. Um dies zu tun, sollte die init() Funktion immer das gleiche Versprechen zurückgeben und nicht jedes Mal erstellen.

Aus diesem Grunde schaffen wir ein latentes Objekt (initializationDeferred) außerhalb der init() Methode und verwenden initializationDeferreddas gleiche Versprechen zurückzukehren jedes Mal init() Methode aufgerufen wird. Wir müssen auch überprüfen, ob der init() bereits schon einmal ausgeführt wurde, wir verwenden die gemeinsam genutzte Variable initializationStarted, um die setTimeout zu überspringen, wenn dies bereits in einem vorherigen Aufruf getan wurde.

nun innerhalb execute können Sie sicher sein, dass die onFulfilled Rückruf von then() nur aufgerufen, wenn init() Methode initialisiert wird.

var initializationDeferred = Q.defer(); // Create here the deferred object so it's common to all init() invocations 
 
var initializationStarted = false; 
 

 
var init = function() { 
 
    if (!initializationStarted) { 
 
    initializationStarted = true; 
 
    setTimeout(function() { 
 
     // initialized 
 
     console.log('Init timeout fired!'); 
 
     initializationDeferred.resolve(true); // Resolve the promise associated to the deferred object 
 
    }, 1000); 
 
    } 
 

 
    return initializationDeferred.promise; // Return the promise associated to the deferred object 
 
}; 
 

 
var execute = function() { 
 

 
    return init().then(function(initialized) { 
 
    // Here your module is initialized and you can do whatever you want 
 
    // The value of "initialized" here is always "true" 
 
    console.log('Execute: initialized?', initialized); 
 
    }); 
 
}; 
 

 
execute().then(function() { 
 
    // This is executed 
 
    console.log('Execute First invocation'); 
 
}); 
 
execute().then(function() { 
 
    // This is executed too 
 
    console.log('Execute Second invocation'); 
 
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/q.js/0.9.2/q.js"></script>

+0

Nein, damit wird die Initialisierung zweimal ausgeführt – Bergi

+0

Ich habe den Code aktualisiert. Überprüfen Sie die Konsolenmeldungen und Sie werden sehen, dass der Init-Code nur einmal ausgeführt wird. – Andrea

+0

Ja, dass 'initializationStarted' gefehlt hat, vielen Dank für die Bearbeitung. – Bergi

Verwandte Themen