使用rxjs过滤和验证返回值的方法

使用rxjs过滤和验证返回值的方法,rxjs,rxjs5,Rxjs,Rxjs5,下面是我试图弄清楚如何使用rxjs实现的场景: 从文件/数据库等加载一些元数据集。元数据中的每个元素都有一个id和其他信息,如实际数据的位置。目前,我正在应用程序开始时异步加载所有这些元数据。加载此数据后,可观察调用完成。最终,我可能会添加一个刷新功能 在应用程序稍后的某个时候,我需要根据元数据中可用的内容加载特定的数据集。我目前正尝试使用类似于fetchData(id:string[]):Observable的函数来实现这一点。这就是我不清楚如何在rxjs范式下进行的地方。我同样不确定如何使用

下面是我试图弄清楚如何使用rxjs实现的场景:

  • 从文件/数据库等加载一些元数据集。元数据中的每个元素都有一个id和其他信息,如实际数据的位置。目前,我正在应用程序开始时异步加载所有这些元数据。加载此数据后,可观察调用完成。最终,我可能会添加一个刷新功能

  • 在应用程序稍后的某个时候,我需要根据元数据中可用的内容加载特定的数据集。我目前正尝试使用类似于fetchData(id:string[]):Observable的函数来实现这一点。这就是我不清楚如何在rxjs范式下进行的地方。我同样不确定如何使用诸如fetchDatum(id:string):Observable之类的函数来请求单个项目

  • 当然,我可以使用过滤器仅对从IMetadata Observable中发出的、与列表中的一个名称匹配的IMetadata数据项进行操作,但我还需要确认在IMetadata Observable发射中找到了所有请求的项,如果没有,我需要出错

    因此,如果有人用id=“Bob”-请求IMetadata,但没有从源Observable发出这样的IMetadata,那么它需要出错。或者,如果他们请求{“Shirley”、“Rex”、“Samantha”},并且没有“Rex”的数据,那么它应该会出错


    我已经考虑过在这里使用Rx.Subject,但从我所读到的内容来看,在rxjs范式下,这通常是不可取的。请说明在rxjs范式下,哪些方法适用于此场景。谢谢

    这是我想出的解决办法。此函数创建一个Observable,该Observable依赖IBufferEvaluator来告诉它如何处理源Observable发出的每个项。它可以将项目附加到缓冲区,跳过发出的项目,清除缓冲区,将缓冲区刷新到订阅服务器,等等。如果找到更好的方法,请告诉我,特别是如果它是现成的rxjs解决方案。谢谢

    import Rx from 'rxjs/Rx';
    
    export enum BufferAction {    
        APPEND, /** Append the current emission to the buffer and continue  **/
        SKIP, /** Do nothing, ignoring the current emission if applicable  **/
        FLUSH, /** This will ignore the current emission, if applicable, and flush the existing buffer contents */
        CLEAR, /** Clear the buffer contents. Ignore the current emission, if applicable */
        COMPLETE, /** Mark the Observable as Complete. The buffer will be cleared upon completion. **/
        APPEND_THEN_FLUSH,   /** Append the current emission to the buffer prior to flushing it  **/
        APPEND_THEN_COMPLETE, /** Append the current emission to the buffer and then complete **/
        CLEAR_THEN_APPEND, /** Clear the buffer contents and then append the current emission to it */
        FLUSH_THEN_APPEND, /** Flush the buffer contents and then append the current emission to it */
        FLUSH_THEN_COMPLETE, /** Flush the buffer contents and then mark the Observable as complete */
        APPEND_FLUSH_COMPLETE /** Append the current emission, flush the buffer, and then complete  */
    }
    
    export function bufferActionToString(action: BufferAction):string
    {
        switch(action)
        {
            case BufferAction.APPEND: return "APPEND";
            case BufferAction.SKIP: return "SKIP";
            case BufferAction.FLUSH: return "FLUSH";
            case BufferAction.CLEAR: return "CLEAR";
            case BufferAction.COMPLETE: return "COMPLETE";
            case BufferAction.APPEND_THEN_FLUSH: return "APPEND_THEN_FLUSH";
            case BufferAction.APPEND_THEN_COMPLETE: return "APPEND_THEN_COMPLETE";
            case BufferAction.CLEAR_THEN_APPEND: return "CLEAR_THEN_APPEND";
            case BufferAction.FLUSH_THEN_APPEND: return "FLUSH_THEN_APPEND";
            case BufferAction.FLUSH_THEN_COMPLETE: return "FLUSH_THEN_COMPLETE";
            case BufferAction.APPEND_FLUSH_COMPLETE: return "APPEND_FLUSH_COMPLETE";
            default: return "Unrecognized Buffer Action [" + action + "]";
        }
    }
    
    export interface IBufferEvaluator<T>
    {
        evalOnNext(next:T, buffer: T[]):BufferAction;
        evalOnComplete(buffer: T[]):BufferAction;
    }
    
    /** bufferWithEval.ts
     *  An Operator that buffers the emissions from the source Observable. As each emission is recieved,
     *  it and the buffered emissions are evaluated to determine what BufferAction to APPEND. You can APPEND
     *  the current emission value to the end of the buffered emissions, you can FLUSH the buffered emissions
     *  before or after appending the current emission value, you can SKIP the current emission value and then
     *  (optionally) FLUSH the buffer, and you can CLEAR the buffer before or after appending the current emission.
     *   
     *  The evalOnNext and evalOnComplete are expected to return a BufferAction to indicate
     *  which action to take. If no evalOnNext is supplied, it will default to APPENDing each emission. The evalOnComplete
     *  will default to FLUSH_THEN_COMPLETE. If evalOnNext or evalOnComplete throw an exception, the Observable will emit 
     *  the exception and cease.
     */
    export function bufferWithEval<T>
        (   source: Rx.Observable<T>, 
            evaluatorFactory?: () => IBufferEvaluator<T>
        ) : Rx.Observable<T[]> 
    {   
        /** if no evaluatorFactory supplied, use the default evaluatorFactory **/
        if(!evaluatorFactory)
        {
            evaluatorFactory = () => {
                return {
                    evalOnNext : function(next: T, buffer: T[]) { return BufferAction.APPEND; },
                    evalOnComplete : function(buffer: T[]) { return BufferAction.FLUSH; }
                };
            }
        }
    
        return new Rx.Observable<T[]>((subscriber: Rx.Subscriber<T[]>) => 
        {
            var _buffer = new Array<T>();          
            var _evaluator = evaluatorFactory();
            var _subscription: Rx.Subscription = null;
    
            function append(next: T)
            {
                _buffer.push(next);
            }
    
            function flush()
            {
                try
                {
                    subscriber.next(_buffer);
                }
                finally
                {
                    // Ignore any exceptions that come from subscriber.next()
                    clear();
                }          
            }
    
            function clear()
            {
                _buffer = new Array<T>();
            }
    
            function next(next: T)
            {
                try
                {
                    var action = _evaluator.evalOnNext(next, _buffer.slice(0));                
                    switch(action)
                    {
                        case BufferAction.APPEND: { append(next); break; }
                        case BufferAction.SKIP: { break; }
                        case BufferAction.FLUSH: { flush(); break; }
                        case BufferAction.CLEAR: { clear(); break; }
                        case BufferAction.COMPLETE: { complete(); break; }
                        case BufferAction.APPEND_THEN_FLUSH: { append(next); flush(); break; }
                        case BufferAction.APPEND_THEN_COMPLETE: { append(next); complete(); break; }
                        case BufferAction.APPEND_FLUSH_COMPLETE: { append(next); flush(); complete(); break; }
                        case BufferAction.CLEAR_THEN_APPEND: { clear(); append(next); break; }
                        case BufferAction.FLUSH_THEN_APPEND: { flush(); append(next); break; }
                        case BufferAction.FLUSH_THEN_COMPLETE: { flush(); complete(); break; }
    
                        default: throw new Error("next(): Invalid BufferAction '" + bufferActionToString(action) + "'");
                    }   
                }
                catch(e)
                {
                    error(e);
                }          
            }    
    
            function complete()
            {
                try
                {            
                    var action = _evaluator.evalOnComplete(_buffer.slice(0));
                    switch(action)
                    {
                        case BufferAction.FLUSH_THEN_COMPLETE:
                        case BufferAction.FLUSH:  { flush(); } 
    
                        case BufferAction.CLEAR: 
                        case BufferAction.COMPLETE: { break; }                   
    
                        case BufferAction.APPEND:
                        case BufferAction.APPEND_THEN_FLUSH:
                        case BufferAction.APPEND_THEN_COMPLETE:
                        case BufferAction.APPEND_FLUSH_COMPLETE:
                        case BufferAction.SKIP: 
                        case BufferAction.CLEAR_THEN_APPEND: 
                        case BufferAction.FLUSH_THEN_APPEND: 
                        default: throw new Error("complete(): Invalid BufferAction '" + bufferActionToString(action) + "'");
                    }
    
                    clear();
                    subscriber.complete();
                    _subscription.unsubscribe();        
                }
                catch(e)
                {
                    error(e);
                }           
            }        
    
            function error(err: any)
            {                  
                try
                {
                    subscriber.error(err);
                }
                finally
                {   
                    _subscription.unsubscribe();
                }
            }          
    
            _subscription = source.subscribe(next, error, complete);
            return _subscription;
        });
    }
    
    从“rxjs/Rx”导入Rx;
    导出枚举缓冲区操作{
    追加,/**将当前发射追加到缓冲区并继续**/
    跳过,/**什么也不做,忽略当前发射(如果适用)**/
    刷新,/**这将忽略当前发射(如果适用),并刷新现有缓冲区内容*/
    清除,/**清除缓冲区内容。忽略当前发射(如果适用)*/
    完成,/**将可观察到的标记为完成。完成后将清除缓冲区**/
    APPEND_然后_FLUSH,/**在刷新前将当前发射附加到缓冲区**/
    APPEND_然后_COMPLETE,/**将当前发射附加到缓冲区,然后完成**/
    清除\然后\追加,/**清除缓冲区内容,然后将当前发射附加到缓冲区*/
    FLUSH\u然后\u APPEND,/**刷新缓冲区内容,然后将当前发射附加到缓冲区*/
    刷新,然后刷新完成,/**刷新缓冲区内容,然后将可观察内容标记为完成*/
    追加\u刷新\u完成/**追加当前发射,刷新缓冲区,然后完成*/
    }
    导出函数bufferActionToString(操作:BufferAction):字符串
    {
    开关(动作)
    {
    case BufferAction.APPEND:返回“APPEND”;
    case BufferAction.SKIP:返回“SKIP”;
    case BufferAction.FLUSH:返回“FLUSH”;
    case BufferAction.CLEAR:返回“CLEAR”;
    case BufferAction.COMPLETE:返回“COMPLETE”;
    case BufferAction.APPEND\u THEN\u FLUSH:返回“APPEND\u THEN\u FLUSH”;
    case BufferAction.APPEND_THEN_COMPLETE:返回“APPEND_THEN_COMPLETE”;
    case BufferAction.CLEAR\u THEN\u APPEND:返回“CLEAR\u THEN\u APPEND”;
    case BufferAction.FLUSH\u THEN\u APPEND:返回“FLUSH\u THEN\u APPEND”;
    case BufferAction.FLUSH\u THEN\u COMPLETE:返回“FLUSH\u THEN\u COMPLETE”;
    case BufferAction.APPEND\u FLUSH\u COMPLETE:返回“APPEND\u FLUSH\u COMPLETE”;
    默认值:返回“无法识别的缓冲区操作[”+操作+“]”;
    }
    }
    导出接口IBufferator
    {
    evalOnNext(next:T,buffer:T[]):BufferAction;
    evalOnComplete(buffer:T[]):BufferAction;
    }
    /**bufferWithEval.ts
    *缓冲可观测源排放的操作员。每次接收到排放物时,
    *对其和缓冲排放进行评估,以确定要附加的缓冲动作。您可以附加
    *当前排放值到缓冲排放的末尾,可以刷新缓冲排放
    *在附加当前发射值之前或之后,可以跳过当前发射值,然后
    *(可选)刷新缓冲区,可以在附加当前发射之前或之后清除缓冲区。
    *   
    *evalOnNext和evalOnComplete预计将返回一个BufferAction以指示
    *采取什么行动。如果未提供evalOnNext,它将默认附加每个排放。逃亡者完成了
    *将默认刷新\u,然后\u完成。如果evalOnNext或evalOnComplete抛出异常,可观察对象将发出
    *例外和停止。
    */
    导出函数bufferWithEval
    (来源:Rx.可观测,
    evaluatorFactory?:()=>iBufferActor
    ):Rx.可观察
    {   
    /**如果未提供evaluatorFactory,请使用默认evaluatorFactory**/
    如果(!evaluatorFactory)
    {
    evaluatorFactory=()=>{
    返回{
    evalOnNext:function(next:T,buffer:T[]){return BufferAction.APPEND;},
    evalOnComplete:函数(buffer:T[]){return BufferAction.FLUSH;}
    };
    }
    }
    返回新的可观察接收((订户:接收订户)=>
    {
    var_buffer=新数组();
    var_evaluator=evaluatorFactory();
    变量订阅:Rx.subscription=null;
    函数追加(下一步:T)
    {
    _buffer.push(下一步);