until封装watch常用逻辑简化代码怎么写(until,watch,开发技术)

时间:2024-05-09 12:30:03 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

1.示例

结合文档的介绍,笔者写了如下的demo代码:

<scriptsetuplang="ts">import{until,invoke}from'@vueuse/core'import{ref}from'vue'constsource=ref(0)invoke(async()=>{awaituntil(source).toBe(4)console.log('满足条件了')})constclickedFn=()=>{source.value++}</script><template><div>{{source}}</div><button@click="clickedFn">点击按钮</button></template>

如上代码所示,规定了当source的值为4的时候触发执行watch回调函数。这里使用到了invoke方法,我们之前接触过,源码如下

exportfunctioninvoke<T>(fn:()=>T):T{returnfn()}

给定参数fn为一个函数,invoke返回函数的执行结果。代码运行效果如下图所示:

until封装watch常用逻辑简化代码怎么写

当点击次数达到4次时,打印了相应的信息。

2.源码

until代码较多,先看两张预览图,了解一下其大概实现:

until封装watch常用逻辑简化代码怎么写

until封装watch常用逻辑简化代码怎么写

通过以上两张图片我们看到until内部定义了很多的用于判断条件是否满足的方法,最后返回的instance也是包含这些方法的对象。下面我们对这些方法逐个分析。

2.1 toMatch

functiontoMatch(condition:(v:any)=>boolean,{flush='sync',deep=false,timeout,throwOnTimeout}:UntilToMatchOptions={},):Promise<T>{letstop:Function|null=nullconstwatcher=newPromise<T>((resolve)=>{stop=watch(r,(v)=>{if(condition(v)!==isNot){stop?.()resolve(v)}},{flush,deep,immediate:true,},)})constpromises=[watcher]if(timeout!=null){promises.push(promiseTimeout(timeout,throwOnTimeout).then(()=>unref(r)).finally(()=>stop?.()),)}returnPromise.race(promises)}

在promise构造函数的参数函数中调用watch API来监听数据源r 。当数据源r的新值代入到条件condition中,使得condition为true时则调用stop停止监听数据源,并将promise状态变为成功。

promise放入promises数组中,如果用户传了timeout选项则promises放入调用promiseTimeout返回的promise实例。最后返回的是Promise.race的结果。看一下promiseTimeout的代码:

exportfunctionpromiseTimeout(ms:number,throwOnTimeout=false,reason='Timeout',):Promise<void>{returnnewPromise((resolve,reject)=>{if(throwOnTimeout)setTimeout(()=>reject(reason),ms)elsesetTimeout(resolve,ms)})}

promiseTimeout返回了一个promise, 如果throwOnTimeout为true则过ms毫秒之后则将promise变为失败状态,否则经过ms毫秒后调用resolve,使promise变为成功状态。

2.2 toBe

functiontoBe<P>(value:MaybeRef<P|T>,options?:UntilToMatchOptions){if(!isRef(value))returntoMatch(v=>v===value,options)const{flush='sync',deep=false,timeout,throwOnTimeout}=options??{}letstop:Function|null=nullconstwatcher=newPromise<T>((resolve)=>{stop=watch([r,value],([v1,v2])=>{if(isNot!==(v1===v2)){stop?.()resolve(v1)}},{flush,deep,immediate:true,},)})//和toMatch相同部分省略}

toBe方法体大部分和toMatch相同,只是watch回调函数不同。这里对数据源r和toBe的参数value进行监听,当r的值和value的值相同时,使promise状态为成功。注意这里的watch使用的是侦听多个源的情况。

2.3 toBeTruthy、toBeNull、toBeUndefined、toBeNaN

functiontoBeTruthy(options?:UntilToMatchOptions){returntoMatch(v=>Boolean(v),options)}functiontoBeNull(options?:UntilToMatchOptions){returntoBe<null>(null,options)}functiontoBeUndefined(options?:UntilToMatchOptions){returntoBe<undefined>(undefined,options)}functiontoBeNaN(options?:UntilToMatchOptions){returntoMatch(Number.isNaN,options)}

toBeTruthy和toBeNaN是对toMatch的封装,toBeNull和toBeUndefined是对toBe的封装。toBeTruthy判断是否为真值,方法是使用Boolean构造函数后判断参数v是否为真值。

toBeNaN判断是否为NAN, 使用的是Number的isNaN作为判断条件,注意toBeNaN的实现不能使用toBe, 因为tobe在做比较的时候使用的是 &lsquo;===&rsquo;这对于NaN是不成立的:

until封装watch常用逻辑简化代码怎么写

toBeNull用于判断是否为null,toBeUndefined用于判断是否为undefined。

2.4 toContains

functiontoContains(value:any,options?:UntilToMatchOptions,){returntoMatch((v)=>{constarray=Array.from(vasany)returnarray.includes(value)||array.includes(unref(value))},options)}

判断数据源v中是否有value,Array.from把v转换为数组,然后使用includes方法判断array中是否包含value。

2.5 changed和changedTimes

functionchanged(options?:UntilToMatchOptions){returnchangedTimes(1,options)}functionchangedTimes(n=1,options?:UntilToMatchOptions){letcount=-1//skiptheimmediatecheckreturntoMatch(()=>{count+=1returncount>=n},options)}

changed用于判断是否改变,通过调用changedTimes和固定第一参数n为1实现的。changedTimes的第一个参数为监听的数据源改变的次数,也是通过调用toMatch实现的,传给toMatch的条件是一个函数,此函数会在数据源改变时调用。每调用一次外层作用域定义的count就会累加一次 ,注意外层作用域count变量声明为-1, 因为时立即监听的。

至此,until源码内定义的函数全部分析完毕,下图总结了这些函数之前的调用关系:

until封装watch常用逻辑简化代码怎么写

源码中最后的返回值也值得我们说一说。

2.6 until返回值&mdash;&mdash;instance

until的返回值分为两种情况:当监听的源数据是数组时和不是数组时,代码如下图所示:

if(Array.isArray(unref(r))){constinstance:UntilArrayInstance<T>={toMatch,toContains,changed,changedTimes,getnot(){isNot=!isNotreturnthis},}returninstance}else{constinstance:UntilValueInstance<T,boolean>={toMatch,toBe,toBeTruthy:toBeTruthyasany,toBeNull:toBeNullasany,toBeNaN,toBeUndefined:toBeUndefinedasany,changed,changedTimes,getnot(){isNot=!isNotreturnthis},}returninstance}

我们看到数据源时数组时返回的方法中没有toBeTruthy,toBeNull,toBeNaN,toBeUndefined这些用于判断基本类型值的方法。另外需要注意的是返回的instance里面有一个get not(){// ...}这是使用getters, 用于获取特定的属性(这里是not)。在getter里面对isNot取反,isNot返回值为this也就是instance本身,所以读取完not属性后可以链式调用其他方法,如下所示:

awaituntil(ref).not.toBeNull()awaituntil(ref).not.toBeTruthy()
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:until封装watch常用逻辑简化代码怎么写的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:JS如何实现时间选择器下一篇:

14 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18