diff --git a/packages/reactive/src/__tests__/async/funcs.test.ts b/packages/reactive/src/__tests__/async/funcs.test.ts index d310a73..2463309 100644 --- a/packages/reactive/src/__tests__/async/funcs.test.ts +++ b/packages/reactive/src/__tests__/async/funcs.test.ts @@ -2,6 +2,11 @@ * * 测试计算属性的getter的第二个参数的各项功能 * + * - 不可重入 + * - 中止信号 + * - 重试 + * + * */ @@ -11,7 +16,8 @@ import { delay } from "flex-tools/async/delay" -describe("异步计算控制功能",()=>{ +describe("异步计算高级控制功能",()=>{ + // 注意:重入时仅会被忽略而不是产生错误 test("控制计算函数的执行的不允许重入执行",()=>{ let cancelCount:number =0 @@ -135,12 +141,19 @@ describe("异步计算控制功能",()=>{ price:2, count:3, total:computed(async (_,{})=>{ + count++ throw new Error("error") },['price','count'],{id:'x',retry:[5,100]}) },{onceComputed:true}) + store.on("computed:error",()=>{ + expect(store.state.total.retry).toBe(0) + }) store.watch((valuePath)=>{ - retryValues.push(store.state.total.retry) - if(retryValues.length===5){ + if(valuePath.some(path=>path[0]==='total' && path[1]==='retry')){ + retryValues.push(store.state.total.retry) + } + // 第一次运行出错,再重试5次,因此retry值为5,4,3,2,1,0 + if(retryValues.length===6){ expect(retryValues).toEqual([5,4,3,2,1,0]) resolve() } @@ -148,6 +161,37 @@ describe("异步计算控制功能",()=>{ }) },0) + test("当执行超时的默认行为",()=>{ + // 执行时loading=true,然后超时后自动设置loading=false,error=TIMEOUT + return new Promise((resolve)=>{ + const store = createStore({ + price:2, + count:3, + total:computed(async (scope,{})=>{ + await delay(500) + return scope.price * scope.count + },['price','count'],{id:'x',timeout:100}) + }) + store.on("computed:cancel",({reason})=>{ + expect(reason).toBe("timeout") + resolve() + }) + store.state.total + }) + }) + test("当执行超时触发错误并导致重试",()=>{ + // 执行时loading=true,然后超时后自动设置loading=false,error=TIMEOUT + return new Promise((resolve)=>{ + const store = createStore({ + price:2, + count:3, + total:computed(async (scope,{})=>{ + await delay(500) + return scope.price * scope.count + },['price','count'],{id:'x',timeout:100}) + }) + }) + }) }) \ No newline at end of file diff --git a/packages/reactive/src/computed/async.ts b/packages/reactive/src/computed/async.ts index 9a05def..386dc34 100644 --- a/packages/reactive/src/computed/async.ts +++ b/packages/reactive/src/computed/async.ts @@ -99,11 +99,13 @@ async function executeComputedGetter(draft:any,computedRu hasAbort=true }) let hasError=false + let hasTimeout=false let computedResult:any for(let i=0;i(draft:any,computedRu // 超时处理 if(timeoutValue>0){ timerId = setTimeout(()=>{ - isTimeout=true + hasTimeout=true if(typeof(timeoutCallback)=='function') timeoutCallback() if(!hasError){ clearInterval(countdownId) @@ -134,12 +136,12 @@ async function executeComputedGetter(draft:any,computedRu // 执行计算函数 computedResult = await getter.call(thisDraft, scopeDraft,computedParams); if(hasAbort) throw new Error("Abort") - if(!isTimeout){ + if(!hasTimeout){ Object.assign(afterUpdated,{result:computedResult,error:null,timeout:0}) } }catch (e:any) { hasError = true - if(!isTimeout){ + if(!hasTimeout){ Object.assign(afterUpdated,{error:getError(e).message,timeout:0}) } /// 启用重试 @@ -151,7 +153,7 @@ async function executeComputedGetter(draft:any,computedRu clearInterval(countdownId) // 重试时不更新loading状态 if(!hasError || (i==retryCount)) Object.assign(afterUpdated,{loading:false}) - if((!hasError && !isTimeout)){ + if((!hasError && !hasTimeout)){ Object.assign(afterUpdated,{error:null}) } updateAsyncComputedState(setState,resultPath,afterUpdated) @@ -165,8 +167,8 @@ async function executeComputedGetter(draft:any,computedRu } } // 计算完成后触发事件 - if(hasAbort){ - store.emit("computed:cancel",{path:valuePath,id,reason:'abort'}) + if(hasAbort || hasTimeout){ + store.emit("computed:cancel",{path:valuePath,id,reason:hasTimeout ? 'timeout' : 'abort'}) }else if(hasError){ store.emit("computed:error",{path:valuePath,id,error:hasError}) }else{ diff --git a/packages/reactive/src/store/types.ts b/packages/reactive/src/store/types.ts index 3b2a844..faa031e 100644 --- a/packages/reactive/src/store/types.ts +++ b/packages/reactive/src/store/types.ts @@ -92,7 +92,7 @@ export type StoreEvents = { 'computed:created' : ComputedObject // 当计算对象创建时 'computed:done' : {path:string[],id:string,value:any} // 当计算函数执行成功后 'computed:error' : {path:string[],id:string,error:any} // 当计算函数执行出错时 - 'computed:cancel' : {path:string[],id:string,reason:string} // 当计算函数被取消时 + 'computed:cancel' : {path:string[],id:string,reason:'timeout' | 'abort' | 'reentry' | 'error'} // 当计算函数被取消时 }; diff --git a/packages/reactive/src/watch/install.ts b/packages/reactive/src/watch/install.ts index 86b72d0..4949569 100644 --- a/packages/reactive/src/watch/install.ts +++ b/packages/reactive/src/watch/install.ts @@ -1,7 +1,5 @@ -import { flush } from "helux" import { OBJECT_PATH_DELIMITER } from "../consts" import { IStore, StoreDefine } from "../store/types" -import { IComputeParams } from "../types" import { setVal } from "../utils" import { WatchDescriptor } from "./types" import { IReactiveReadHookParams } from "../reactives/types" @@ -33,8 +31,7 @@ export function installWatch(params:IReactiveReadHookPara // @ts-ignore store.stateCtx.setState((draft)=>{ setVal(draft,params.path,watchDescriptor.options.initial) - }) - flush(store.stateCtx.state as any) + }) } return watchObject }