2017-05-22 1 views
-3

La question suivante est tirée d'une interview. J'ai été capable de résoudre certaines parties, mais je suis resté coincé:Réparer le bug! (comment appeler une fonction asynchrone dans une fonction synchrone)

Correction du bug dans le code suivant. DataContainer est un wrapper autour de la base de données fournissant le cache pour les données extraites de la base de données.

appeler devrait chercher d'extraction des données de la base de données via DbConnection. Si la récupération réussit, elle doit renvoyer true; sinon, il doit renvoyer false. L'appel getData doit renvoyer des données mises en cache ou déclencher une exception si les données n'ont pas encore été extraites.

function DataContainer(connectionString) { 
    var dataFetched = false; 
    var dbConnection = DbConnection(connectionString); 
} 

DataContainer.prototype.getData = function() { 
    if (!this.dataFetched) 
    throw "Data not fetched!"; 
    return this.data; 
} 

DataContainer.prototype.fetch = function() { 
    this.dbConnection.getAllData(function (err, result) { 
    if (err) { 
     delete this.data; 
     this.dataFetched = false; 
     return false; 
    } else { 
     this.data = result; 
     this.dataFetched = true; 
     return true; 
    } 
    }); 
} 

// Mock of DbConnection for testing purposes: 
function DbConnection(connectionString) { } 

DbConnection.prototype.getAllData = function (callback) { 
    callback(null, [1, 2, 3]); 
} 

//Expected: 1, 2, 3 
var dc = new DataContainer('connection'); 
if (dc.fetch()) { 
    var data = dc.getData(); 
    for (var i = 0; i < data.length; i++) { 
    console.log(data[i]); 
    } 
} 

Je fixe le code autant que possible, y compris la création de nouveaux DbConnection objet dans la fonction constructeur, la définition des propriétés avec ce mot-clé au lieu de var dans la fonction constructeur, et la liaison ce à la fonction de rappel lors de l'appel getData (regardez le code suivant). Le seul problème restant est comment appeler une fonction asynchrone (getData) dans une fonction synchrone ?!

function DataContainer(connectionString) { 
    this.dataFetched = false; 
    this.dbConnection = new DbConnection(connectionString); 
} 

DataContainer.prototype.getData = function() { 
    if (!this.dataFetched) 
    throw "Data not fetched!"; 
    return this.data; 
} 

DataContainer.prototype.fetch = function() { 
    this.dbConnection.getAllData(function (err, result) { 
    if (err) { 
     delete this.data; 
     this.dataFetched = false; 
     return false; 
    } else { 
     this.data = result; 
     this.dataFetched = true; 
     return true; 
     } 
    }.bind(this)); 
} 

est une d'extraction fonction synchrone et nous ne sommes pas autorisés à le rendre asynchrone. getData est une fonction asynchrone et nous n'avons pas le droit de la rendre synchrone. Maintenant, comment pouvons-nous utiliser getData à l'intérieur aller chercher ???

Répondre

1

fetch est synchrone, mais getAllData est asynchrone, donc la question est de savoir comment faire getAllData se comporter comme s'il s'agissait d'une fonction synchrone. Un (et peut-être la seule) façon dont vous pourriez y parvenir est en utilisant async/await:

DataContainer.prototype.fetch = async function fetch() { 
    return await new Promise(resolve => { 
     this.dbConnection.getAllData((err, result) => { 
     if (err) { 
      delete this.data; 
      this.dataFetched = false; 
     } else { 
      this.data = result; 
      this.dataFetched = true; 
     } 
     resolve(this.dataFetched); 
     }); 
    }); 
} 

Cela permettra au code de la consommation pour traiter l'appel comme une opération synchrone