nestjs中的Observables-异步读取文件

时间:2019-02-19 15:19:17

标签: node.js rxjs observable nestjs behaviorsubject

我正在尝试一个用例,它异步读取json文件,并将其作为响应发送出去(作为rxjs可观察的数据)。这是我使用的服务

 import { logger } from './../../shared/utils/logger';
import { Injectable } from '@nestjs/common';
import * as fs from 'fs';
import * as path from 'path';
import { BehaviorSubject, Observable, pipe, of, from, throwError, merge} from 'rxjs';
import { map, filter, scan, take, debounce, switchMap, retry, catchError, mergeMap, delay, zip, tap, mapTo } from 'rxjs/operators';
import { HttpResponseModel } from '../model/config.model';
import { isNullOrUndefined } from 'util';
@Injectable()
export class NewProviderService {
    serviceSubject: BehaviorSubject<HttpResponseModel[]>;
    filePath: string;
    httpResponseObjectArray: HttpResponseModel[];
    constructor() {
        this.serviceSubject = new BehaviorSubject<HttpResponseModel[]>([]);
        this.filePath = path.resolve(__dirname, './../../shared/assets/httpTest.json');
        this.setSubject();
    }


 readFileFromJSON() {
      this.readFileFromJsonSync();
      fs.exists(this.filePath.toString(), exists => {
        if (exists) {
           fs.readFile(this.filePath.toString(), 'utf-8', (err, data) => {
                logger.info('file read without parsin', data);
                this.httpResponseObjectArray = JSON.parse(data).HttpTestResponse;
                logger.info('array obj is:', this.httpResponseObjectArray);
                logger.info('file read after parsing', JSON.parse(data));
                return this.httpResponseObjectArray;
            });
        } else {
            return null;
        }

    });
}


getObservable(): Observable<HttpResponseModel[]> {
       // create an observable
        // return Observable.create(observer => {
        //     observer.next(this.readFileFromJSON());
        // });

        return of(this.readFileFromJsonSync()).pipe(map(data => {
            logger.info('inside obs methid', data);
            return data;
        }));

    }

    setSubject() {
        this.getObservable().subscribe(data => {
            logger.info('data before setting in sub', data);
            this.serviceSubject.next(data);
        });
    }
}

因此,我想在控制器中订阅这个发出的可观察到的东西,但是在订阅并阅读主题(BehaviorSubject)之后,就可以读取这些值。我了解我在订阅和发送数据方面做错了一些事情,但无法理解我在哪里做错了。每次控制器打印“未订阅的数据已预订” ,然后继续读取文件并发出可观察的

这是控制器数据

@Get('/getJsonData')
  public async getJsonData(@Req() requestAnimationFrame, @Res() res) {
    this.newService.serviceSubject.subscribe(data => {
      logger.info('data subscribed', data);
      res.status(HttpStatus.OK).send(data);
    });

  }

如果我同步读取文件,效果很好

使用以下方法替换readFileFromJSON(),效果很好

readFileFromJsonSync(): HttpResponseModel[] {
        const objRead = JSON.parse(fs.readFileSync(this.filePath.toString(), {encoding: 'utf-8'}));
        logger.info('object read is', objRead.HttpTestResponse);
        return objRead.HttpTestResponse;

    }

所以我在异步读取文件时丢失了一些东西。我不确定我在做什么错。有人可以帮忙吗?

1 个答案:

答案 0 :(得分:0)

问题是您实际上没有在readFileFromJSON中返回任何内容。它将异步运行fs.existsfs.readFile以及相应的回调,但是这些回调的结果将被忽略。

您应该改用Promises。您既可以自己创建Promise,也可以使用诸如bluebird之类的库将fs从基于回调的API转换为基于Promise的API。有关更多信息,请参见this thread

return new Promise(function(resolve, reject) {
    fs.readFile(this.filePath.toString(), 'utf-8', (err, data) => {
        if (err) {
            reject(err); 
        } else {
            const httpResponseObjectArray = JSON.parse(data).HttpTestResponse;
            resolve(httpResponseObjectArray);
        }
    });
});