UNPKG

yinxing

Version:
394 lines (374 loc) 8.25 kB
//https://www.learnrxjs.io/operators/transformation/mergescan.html //https://rxjs.dev/api/index/function/forkJoin const R=require('ramda') const rxjs=require("rxjs") const op=require('rxjs/operators') const { ajax, AjaxResponse, AjaxError, AjaxTimeoutError, }=require('rxjs/ajax') const { ArgumentOutOfRangeError, AsyncSubject, BehaviorSubject, ConnectableObservable, EMPTY, EmptyError, GroupedObservable, NEVER, Notification, NotificationKind, ObjectUnsubscribedError, Observable, ReplaySubject, Scheduler, Subject, Subscriber, Subscription, TimeoutError, UnsubscriptionError, VirtualAction, VirtualTimeScheduler, animationFrameScheduler, asapScheduler, asyncScheduler, bindCallback, bindNodeCallback, combineLatest, concat, config, defer, empty, forkJoin, from, fromEvent, fromEventPattern, generate, identity, iif, interval, isObservable, merge, never, noop, observable, of, onErrorResumeNext, pairs, partition, pipe, queueScheduler, race, range, scheduled, throwError, timer, using, zip, }=rxjs const { audit, auditTime, buffer, bufferCount, bufferTime, bufferToggle, bufferWhen, catchError, combineAll, //combineLatest, //concat, concatAll, concatMap, concatMapTo, count, debounce, debounceTime, defaultIfEmpty, delay, delayWhen, dematerialize, distinct, distinctUntilChanged, distinctUntilKeyChanged, elementAt, endWith, every, exhaust, exhaustMap, expand, filter, finalize, find, findIndex, first, flatMap, groupBy, ignoreElements, isEmpty, last, map, mapTo, materialize, max, //merge, mergeAll, mergeMap, mergeMapTo, mergeScan, min, multicast, observeOn, //onErrorResumeNext, pairwise, //partition, pluck, publish, publishBehavior, publishLast, publishReplay, //race, reduce, refCount, repeat, repeatWhen, retry, retryWhen, sample, sampleTime, scan, sequenceEqual, share, shareReplay, single, skip, skipLast, skipUntil, skipWhile, startWith, subscribeOn, switchAll, switchMap, switchMapTo, take, takeLast, takeUntil, takeWhile, tap, throttle, throttleTime, throwIfEmpty, timeInterval, timeout, timeoutWith, timestamp, toArray, //window, windowCount, windowTime, windowToggle, windowWhen, withLatestFrom, //zip, zipAll, }=op const say=(x="")=>(y="")=>(console.log(x,y),y) const say1=(x="")=>async (y="")=>(console.log(x,await y),y) const init_result=(t=[])=>({ ok:new Set(), fail:new Set(t), times:0, result:{}, e:{}, }) const seq2=(t=[],time=1000)=>from(t) .pipe( op.zip( interval(time) .pipe(take(t.length)) ) ) //同步 //只重试失败的部分 //------------------------------------------------------------------------ const seq_safe=(fn,t=[],max_retry_times=3)=>{ if (R.isEmpty(t)) throw "????" let r0={ ok:new Set(), fail:new Set(t), times:0, result:{}, } let d=from(t) .pipe( scan((a,b)=>{ a.times += 1 try{ let r=fn(b) a.ok.add(b) a.result[b]=r a.fail.delete(b) return a }catch(e){ throw a } },r0), retryWhen(e=>e.pipe( takeWhile(x=>x.fail.size>0), take(max_retry_times), tap(say('retry')), scan((a,b)=>(console.log('retry : #',a),a+1),0), delayWhen(x => timer(x * 1000)), //delay(1000), )), ) return d } //异步 //全量重试 //------------------------------------------------------------------------ const seq_safe_async=(fn,t=[],max_retry_times=3)=>{ if (R.isEmpty(t)) throw "????" let d=of(t) .pipe( mergeMap(x=>forkJoin(...x.map(fn))), retryWhen(e=>e.pipe( //tap(say('retry')), take(max_retry_times), scan((a,b)=>(console.log('retry : #',a),a+1),0), delayWhen(x => timer(x * 1000)), //delay(1000), )), ) return d } //异步 //全量重试 const seq_safe_async2=(fn,t=[],max_retry_times=3)=>{ if (R.isEmpty(t)) throw "????" let r0=init_result(t) const run=async y=>{ try{ return [y,await fn(y)] }catch(e){ return [y,{ok:false,e}] } } let d=of(t) .pipe( tap(say('----')), mergeMap(x=>forkJoin([...x].map(run))), scan((a,b,i)=>{ a.times+=1 b.forEach(([x,y])=>{ if (y.ok){ a.result[x]=y a.ok.add(x) a.fail.delete(x) }else{ a.e[x]=y.e throw a } }) return a },r0), retryWhen(e=>e.pipe( //tap(say('retry')), scan((a,b)=>(console.log('retry : #',a),a+1),0), delayWhen(x => timer(x * 1000)), take(max_retry_times), ) ), //retry(4), ) return d } //异步 //只重试失败部分 //------------------------------------------------------------------------ const seq_safe_async3=(fn,t=[],max_retry_times=3)=>{ if (R.isEmpty(t)) throw "????" const reducer=(a,b,i) => { //console.log('$$$$$',a,b,i) ++a.times let todo=[...a.fail] let run=async x=>{ try{ let r=await fn(x) a.ok.add(x) a.result[x]=r a.fail.delete(x) return a }catch(e){ a.e[x]=e throw a } } return forkJoin(todo.map(run)) // } let r0=init_result(t) let d=of(t) .pipe( mergeScan(reducer,r0), //op.combineLatest(), mergeAll(), retryWhen(e=>e.pipe( //tap(say('retry')), takeWhile(x=>x.fail.size>0), take(max_retry_times), scan((a,b)=>(console.log('retry : #',a),a+1),0), delayWhen(x => timer(x * 1000)), //delay(1000), )), takeLast(1), ) return d } //异步 //只重试失败部分 //------------------------------------------------------------------------ const seq_safe_async4=(fn,t=[],max_retry_times=3)=>{ if (R.isEmpty(t)) throw "????" const reducer=async (a,b,i)=>{ a.times++ try{ let r=await fn(b) a.result[b]=r a.ok.add(b) a.fail.delete(b) return a }catch(e){ a.e[b]=e throw a } } let r0=init_result(t) let d=from(t) .pipe( mergeScan((a,b,i) => forkJoin(reducer(a,b,i)),r0), map(x=>x[0]), retryWhen(e=>e.pipe( //tap(say('retry')), takeWhile(x=>x.fail.size>0), take(max_retry_times), scan((a,b)=>(console.log('retry : #',a),a+1),0), delayWhen(x => timer(x * 1000)), //delay(1000), )), // retry(3), takeLast(1), ) return d } module.exports={ say, say1, seq2, seq_safe, seq_safe_async, seq_safe_async2, seq_safe_async3, seq_safe_async4, }