2017-09-27 3 views
1

Je n'aime pas tout ce que j'ai vu jusqu'à présent ...Existe-t-il un modèle commun pour les modules de noeud qui doivent charger async de gros fichiers avant qu'ils ne soient utiles?

Module

import lineReader from 'line-reader' 

let bigFile = './huge-file.csv' 

export default class DooDad { 

    constructor() { 
     this.dictionary = new Map() 
     // Something like this seems like it'd be nice... 
     // await this.load() 
    } 

    load() { 
     return new Promise((resolve, reject) => { 
      lineReader.eachLine(bigFile, (line, last) => { 
       // this.dictionary = The contents of huge-file.csv 
      }) 
     }) 
    } 

    doStuff(foo) { 
     // Uses this.dictionary to do something interesting 
     // Problem: Unusable without first calling and waiting for this.load() 
    } 
} 

Utilisation

import DooDad from '../doodad' 

let doodad = new DooDad() 

// We have to first call and wait for load() before doodad is useable 
doodad.load().then(x => { 
    doodad.doStuff() 
}) 

On dirait que vous voulez soit voulez ...

1) Rendre le chargement synchrone

2) Faire unstatique fonctionsur Doodad qui retourne une promesse qui résout une nouvelle instance d'un Doodad

3) Faites le constructeur retourne une promesse (semble bizarre) Asynchronous constructor

4) Emet un événement lorsque le chargement effectué

5) Laisser comme il est

6) ????

Répondre

2

doodad.load().then() est parfaitement logique pour moi. Vous ne voulez pas que les constructeurs soient asynchrones, donc il est logique d'avoir .load() là où se trouvent les choses asynchrones.

L'autre modèle que j'ai vu est vous exportez une fonction de type usine qui renvoie une promesse et lorsque cette promesse est résolue, la valeur résolue est votre objet entièrement formé. Cela a l'avantage de ne pas avoir accès à l'objet tant que la tâche asynchrone n'est pas terminée et qu'il n'y a pas de tentation en appelant du code pour essayer de l'utiliser avant qu'il ne soit prêt.

import makeDooDad from '../doodad' 

makeDooDad().then(doodad => { 
    // you only get access to the object here after it's been fully 
    // initialized 
    doodad.doStuff(); 
}); 

Et, la fonction d'usine makeDooDad() fait quelque chose comme cela à l'intérieur de votre module:

En ce qui concerne vos autres options:

Faire le chargement synchrone

Cela pourrait être OK seulement s'il est seulement fait à l'étoile du serveur temps de tup. Il n'y a généralement pas de coût réel pour faire des E/S synchrones au démarrage du serveur et cela rend souvent les choses beaucoup plus simples. Par exemple, require() fait lui-même des E/S synchrones.

Faire une fonction créer statique sur Doodad qui retourne une promesse qui résout une nouvelle instance d'un Doodad

qui est essentiellement ce que je recommande ci-dessus avec la fonction d'usine. C'est souvent une bonne option.

Faire le constructeur retourne une promesse (semble bizarre) constructeur Asynchronous

Non Ne pas vraiment envie de le faire. Les constructeurs doivent renvoyer des objets, pas des promesses. Utilisez une fonction d'usine pour renvoyer une promesse.

un événement émettons lorsque son chargement effectué

Il y a d'autres morceaux de code qui font tels que la création d'un WriteStream, émet un événement open sur le flux lorsque le flux est en fait ouvert. Mais, à l'époque des promesses, ce n'est pas ma façon préférée de faire les choses pour d'autres types d'objets qui n'utilisent pas déjà beaucoup d'événements.

Laissez-le comment il est

Il est OK comme il est, mais je préfère la fonction d'usine qui retourne une promesse.

+0

Bons points. J'aime la synchronisation et quand cela n'a pas de sens, je suis vendu en usine sur la base de 'Ceci a l'avantage de ne pas avoir accès à l'objet'. – Jason

+0

@Jason - Si cela répond à votre question, vous pouvez l'indiquer à la communauté en cliquant sur la coche à gauche de la réponse et aussi gagner des points de réputation pour suivre la procédure appropriée ici sur débordement de pile. – jfriend00