是否存在需要在大文件有用之前异步加载大型文件的节点模块的通用模式?

时间:2017-09-27 20:54:23

标签: node.js asynchronous control-flow

我不喜欢到目前为止所看到的任何事情......

模块

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()
    }
}

用法

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()
})

好像你要么......

1)使加载同步

2)在DooDad上创建一个静态create函数,该函数返回一个解析为DooDad新实例的promise

3)使构造函数返回Promise(看起来很奇怪)Asynchronous constructor

4)完成加载后发出一个事件

5)保持原样

6)????

1 个答案:

答案 0 :(得分:2)

doodad.load().then()对我来说非常有意义。您不希望构造函数是异步的,因此让.load()成为异步内容的位置是有意义的。

我见过的另一种模式是导出一个返回promise的工厂类型函数,当解析该promise时,解析后的值就是完全形成的对象。这样做的好处是,在完成异步操作之前无法访问该对象,并且在准备好之前调用代码尝试使用它是没有诱惑的。

import makeDooDad from '../doodad'

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

而且,makeDooDad()工厂函数在模块内部执行类似的操作:

function makeDooDad() {
   let d = new DooDad();
   // fully initialize the doodad object before resolving the promise
   // and before returning the object
   return d.load().then(() => {
       // let the object itself by the resolved value
       return d;
   });
}

至于你的其他选择:

  

使加载同步

仅当它仅在服务器启动时完成时才可以。在服务器启动时执行某些同步I / O通常没有实际成本,并且通常会使事情变得更加简单。例如,require()本身执行同步I / O.

  

在DooDad上创建一个静态创建函数,该函数返回一个解析为DooDad的新实例的promise

这基本上就是我上面推荐的工厂功能。这通常是一个不错的选择。

  

让构造函数返回一个Promise(看起来很奇怪)异步构造函数

没有。真的不想那样做。构造函数应返回对象,而不是承诺。使用工厂函数返回承诺。

  

完成加载时发出事件

还有其他一些代码可以执行此操作,例如创建writeStream,当流实际打开时,会在流上发出open事件。但是,在承诺的时代,对于尚未使用大量事件的其他类型的对象,这不是我最喜欢的做事方式。

  

保持原样

它没关系,但我更喜欢返回承诺的工厂函数。