Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Form 性能优化意见征集 #1049

Closed
tangjinzhou opened this issue Aug 2, 2019 · 62 comments
Closed

Form 性能优化意见征集 #1049

tangjinzhou opened this issue Aug 2, 2019 · 62 comments

Comments

@tangjinzhou
Copy link
Member

tangjinzhou commented Aug 2, 2019

What problem does this feature solve?

Form组件过多时的性能问题
现在的 Form 组件里的任一 FormItem 变化都会导致 Form 所在的上下文触发更新,当上下文中组件过多时,会变得卡顿。
现在添加 :selfUpdate="true" 属性,将FormItem 变为独立更新,避免整个组件刷新。同样也带来了新的问题:如有其它依赖该表单项值的地方,则不可以使用。

What does the proposed API look like?

<template>
  <a-form :form="form">
    <a-form-item key="A" ref="formA">
        <a-input v-if="form.getFieldValue('B') === 'abc'" v-decorator="['A']" />
    </a-form-item>
    <a-form-item key="B" selfUpdate>
       <a-input v-decorator="['B']"  />
    </a-form-item>
  </form>
</template>
@QifanChan
Copy link

还有hideRequiredMark这个属性不起效果

@QifanChan
Copy link

這個已經發到正式版本了嗎?可以使用嗎

@QifanChan
Copy link

很好奇,官网的form页面中input就不卡,我分析过是我的页面里存在大量的select,有很多的options,当选择select后,再去进行input的操作,就会变得很卡,用了上述api,但是没有效果

@yi-huan
Copy link

yi-huan commented Aug 2, 2019

@QifanChan 我的是输入就卡了。特别是火狐浏览器,输入中文时,谷歌相对好点。

@yi-huan
Copy link

yi-huan commented Aug 5, 2019

还有一种情况就是一个页面有多个 form, 多个 form 的表单数量合起来多也会卡,单个 form 里的表单的数量少没用。还打算拆分多个 form 看能不能去除这个影响

@QifanChan
Copy link

QifanChan commented Aug 5, 2019 via email

@KyLeoHC
Copy link

KyLeoHC commented Aug 6, 2019

组件多的话,尤其是form,input输入确实卡,我现在的临时解决方案是只能自己基于ant的input样式,单独写一个简化版的input组件,然后debounce延时执行this.$emit('input', event),不会频繁触发input事件。目前来看,实际项目中效果还好,不会很卡。

@QifanChan
Copy link

QifanChan commented Aug 6, 2019 via email

@KyLeoHC
Copy link

KyLeoHC commented Aug 6, 2019

我目前也是这么做的,但是会有一个点,在页面大量存在select的时候,options比较多的时候,input照样会卡顿,你可以试一下

我这边目前还好,如果options太多的话,我会直接重写整个select组件(减少组件嵌套使用、精简逻辑等等),这样也能进一步提升性能。你可以试试。
我目前重写了a-table组件,为的是支持需要不分页、直接渲染全部数据的场景(当然也有一些定制功能增加)。

@yi-huan
Copy link

yi-huan commented Aug 7, 2019

组件多的话,尤其是form,input输入确实卡,我现在的临时解决方案是只能自己基于ant的input样式,单独写一个简化版的input组件,然后debounce延时执行this.$emit('input', event),不会频繁触发input事件。目前来看,实际项目中效果还好,不会很卡。

听你这样说,那把 input 组件 的 this.$emit('input', e)compositionstart compositionend加个判断,在输入中文这种拼写的时候不执行 this.$emit('input', e) ,这样也会好一点。
延时的话我觉得会有点停顿

@KyLeoHC
Copy link

KyLeoHC commented Aug 7, 2019

组件多的话,尤其是form,input输入确实卡,我现在的临时解决方案是只能自己基于ant的input样式,单独写一个简化版的input组件,然后debounce延时执行this.$emit('input', event),不会频繁触发input事件。目前来看,实际项目中效果还好,不会很卡。

听你这样说,那把 input 组件 的 this.$emit('input', e)compositionstart compositionend加个判断,在输入中文这种拼写的时候不执行 this.$emit('input', e) ,这样也会好一点。
延时的话我觉得会有点停顿

不会停顿,只是同步数据给调用方的时候有延迟(这里存在隐患,如果在延时时间内,你是拿不到最新的值)。

@QifanChan
Copy link

QifanChan commented Aug 7, 2019 via email

@zijingsong
Copy link

个人觉得Form表单还是改成和element还有iview一样的直接表单数据驱动比较好,现在单独封装在表单容器中,多了很多概念,而且使用起来好麻烦

@shudingbo
Copy link
Contributor

shudingbo commented Aug 16, 2019

页面 同时 包含 a-from 和 a-table 组件时,a-form 里输入数据,会导致 a-table里的数据重新渲染,这个就导致卡了... 。 如 下面,只要在a-form的任意控件里输入或值变化,都会导致 a-table 数据重新渲染,如果 a-table数据稍微多点(>50),就卡的很

<template>
  <div>
    <div>
    <a-form layout="inline" :form="form" @submit="handleSubmit">
      <a-form-item label="ID">
        <a-input
          v-decorator="['UserID',{ rules: [{ required: true, message: '请输入要查找的ID!' }],initialValue:0}]"
          placeholder="ID"
        >
        </a-input>
      </a-form-item>
      <a-form-item label="日期选择">
        <a-range-picker v-decorator="['selTm',
        {
          rules: [{ type: 'array', required: true, message: '请选择查找时间!' }],
          initialValue: [defaultSelDate.sDate, defaultSelDate.eDate]
        }]"/>
      </a-form-item>
      <a-form-item>
        <a-select :value="query.style" style="width: 140px" @change="val=>this.query.style=val" >
        </a-select>
      </a-form-item>
      <a-form-item>
        <a-button type="primary" html-type="submit">查找</a-button>
      </a-form-item>
    </a-form>
    </div>
    <div style="height:600px;overflow-y: scroll;">
    <a-spin :spinning="spinning">
      <a-table :dataSource="data" :columns="columns" rowKey="RowNum" :pagination="false" @change="changePage" size="middle" bordered>
      </a-table>
    </a-spin>
    </div>
  </div>
</template>

@shudingbo
Copy link
Contributor

from 数据变化,不要重新渲染其它控件

@okool
Copy link

okool commented Aug 21, 2019

从Jquery时代到现在,处理表单,验证表单和获取表单内容都是一场恶梦.
一个简单的表单动不动就行几百行代码,还经常写错.
不管用哪个框架,真正业务从来没用标签式表单,而是使用配置表单.类似的还有配置表格.
可以参考.
举例:

<script>
data(){
formFields:[
{
        label: '头像',
        name: 'avatar',
        render(h,src, form){
          return <Avatar src={src}/>
        }
      },
      {
        label: '姓名',
        name: 'name',
        default:'张三',
        rules: [{
          required: true,
          message: '姓名不能为空',
        }],
        render(h){
          return <Input placeholder="真实姓名" />
        }
      }
];
}
methods:{
 onSubmit(formData){
        console.log(formData);
       // ...todo
  }
 onReset(){
 }
}
</script>
<template>
 <my-form
      :fields="formFields" 
     @submit="onSubmit" 
     @reset="onReset" 
>
         <button slot="submit" >提交</button>
        <button slot="reset" >重置</button>
</my-form>
</template>

@QifanChan
Copy link

QifanChan commented Aug 21, 2019 via email

@okool
Copy link

okool commented Aug 21, 2019

。。。你这个貌似是从antdesign的react版本拿过来的

哦,我只是举个"配置表单"的例子.
因为业务中我react和vue都写,所以使用了JSX写法,vue和react都通用.
自定义渲染和优化放在my-form里在实现.每个form-item都能控制,没有发现卡顿的情况.

表单卡顿一般出现在输入框类型,如input,textArea.富文本.这种类型的组件需要自己写渲染逻辑,而不是使用react或vue自带的双向绑定逻辑.简单点就是对比 原生input的value值和data里的值是否一致,,一致则不触发渲染和input事件.尽量不要使用延时渲染.延时渲染会导致数据不干净.

@QifanChan
Copy link

QifanChan commented Aug 21, 2019 via email

@zhangshichuan
Copy link

😌. 难受. 项目都做完了, 才看到这个 issue.

@QifanChan
Copy link

QifanChan commented Aug 23, 2019 via email

tangjinzhou added a commit that referenced this issue Aug 30, 2019
@lk1942
Copy link

lk1942 commented Aug 30, 2019

selfUpdate效果很明显

@tangjinzhou
Copy link
Member Author

tangjinzhou commented Aug 30, 2019

1.3.17-beta.1 已发布 欢迎体验

selfUpdate

设置 selfUpdatetrue 后,Form 通过增量方式更新,只更新被修改的字段。大部分场景下,你只需要编写代码即可。而在某些特定场景,例如修改某个字段值后出现新的字段选项、或者纯粹希望表单任意变化都需要进行渲染。你可以通过修改 Form.Item 取消 selfUpdate,或者在 change / onValuesChange 回调中手动调用 this.$forceUpdate() 更新组件。

如果你并不精通 Vue,并不建议使用 selfUpdate,如果出现性能问题,可以尝试这把 Form 相关的业务独立到一个单独的组件中,减少组件渲染的消耗。

@zhangshichuan
Copy link

very good!

@QifanChan
Copy link

very good!
有代码吗?看下你怎么是用的

@nongzhenli
Copy link

我们通常会选择在扩展的validator中写自定义的校验规则,内部其实使用回调达到异步的效果,建议你也试用下哈,而不要使用@input@change去做处理,

感谢!我目前也是通过 vvalidator 中设置 trigger

image

但是触发时机依然是每次更改值都会被触发一次。很纳闷更改了收集的时机,依然会每次变更至都会触发的问题

@QifanChan
Copy link

QifanChan commented Apr 16, 2020 via email

@nongzhenli
Copy link

看写法你是重复性使用一些东西了,造成了现在的困扰,建议好好看下他们给的demo哈

好的,谢谢!

@nongzhenli
Copy link

nongzhenli commented Apr 16, 2020

看写法你是重复性使用一些东西了,造成了现在的困扰,建议好好看下他们给的demo哈

方便来个vx吗?想请教下。 wojia957321

@iamwjj
Copy link

iamwjj commented May 7, 2020

看一下吧,这个现在已经解决了update

解决了吗?我加了selfUpdate没效果。。

@iamwjj
Copy link

iamwjj commented May 7, 2020

难道是我直接用v-model绑定的原因吗?

@QifanChan
Copy link

QifanChan commented May 7, 2020 via email

@iamwjj
Copy link

iamwjj commented May 7, 2020

不要混用

混用什么?页面内的表单控件都是直接用v-model的

@yinxianwei
Copy link

表单就不建议用v-model, 用v-model的话, 建议更新1.5.0使用FormModel

@JinPengGeng
Copy link

@yinxianwei FormModel 目前并不支持 selfUpdate,所以同时使用 FormModel 和 v-model 还是会卡顿的

@shasharoman
Copy link

shasharoman commented Jun 19, 2020

不要混用

同样没搞懂混用的意思,我是这样写的:

<a-form><a-form-item>...input v-model...</a-form-item></a-form>

然后加selfUpdate之后发现没有效果,卡顿的原因是因为form里有一个select里面包含300+option

@hy08
Copy link

hy08 commented Jul 2, 2020

页面中同时有FormModel和Table,改变FormModel中Input组件,table也会渲染,而且没有selfUpdate,table数据多了就卡的飞起

@hy08
Copy link

hy08 commented Aug 13, 2020

1.6.1版本,添加selfUpdate无效。整个Form都在刷新

@bobchen554
Copy link

这貌似是vue 函数式组件的性能问题

@QifanChan
Copy link

QifanChan commented Sep 11, 2020 via email

@fwgood fwgood mentioned this issue Oct 17, 2020
9 tasks
@fwgood
Copy link

fwgood commented Oct 17, 2020

通过key查找formItem的时候直接使用了Object.keys来获取键,只能拿到第一层的key,导致全部失效 提交了pr来修复 #2999

@daliweiwei
Copy link

能否支持 Form中嵌套table 支持多行数据动态验证

@nqsjd178559344
Copy link

真的好卡嘤

@lxj665294
Copy link

目前遇到的情况是,当输入框遇上table就有输入卡顿的问题

@yanguangying
Copy link

都2021年了,这个还在这放着呢!

@dev-zl
Copy link

dev-zl commented Jan 29, 2021

我是 在vue 里面的 flushSchedulerQueue 方法 中处理的,性能完美解决 一点不卡 。
@yanguangying @Amanda5293 @nqsjd178559344 @hy08 @bobchen554 @QifanChan @nongzhenli
@shasharoman

@dev-zl
Copy link

dev-zl commented Jan 29, 2021

我是在vue里面的flushSchedulerQueue方法中处理的,性能完美解决一点一
点卡 。@yanguangying @ Amanda5293 @ nqsjd178559344 @ hy08 @ bobchen554 @QifanChan @nongzhenli
@shasharoman @zhangshichuan

@dev-zl
Copy link

dev-zl commented Jan 29, 2021

我是在vue里面的flushSchedulerQueue方法中处理的,性能完美解决一点一
点卡 。@yanguangying @ Amanda5293 @ nqsjd178559344 @ hy08 @ bobchen554 @QifanChan @nongzhenli
@shasharoman @zhangshichuan

性能慢的问题原因是: 会触发其它 component 的 watchers ,我的做法是:
以 a-input 为例

1 首先在vue 中 自定义 一个全局函数 tempCloseCallUpdatedHooks
var tempCloseCallUpdatedHooks=false; Vue.prototype.$tempCloseCallUpdatedHooks=function () { tempCloseCallUpdatedHooks=true; }
2 在 vue 中 flushSchedulerQueue 函数内的新增逻辑
`function flushSchedulerQueue () {
currentFlushTimestamp = getNow();
flushing = true;
var watcher, id;

// Sort queue before flush.
// This ensures that:
// 1. Components are updated from parent to child. (because parent is always
// created before the child)
// 2. A component's user watchers are run before its render watcher (because
// user watchers are created before the render watcher)
// 3. If a component is destroyed during a parent component's watcher run,
// its watchers can be skipped.
queue.sort(function (a, b) { return a.id - b.id; });

// do not cache length because more watchers might be pushed
// as we run existing watchers
for (index = 0; index < queue.length; index++) {
watcher = queue[index];
if (watcher.before) {
watcher.before();
}
id = watcher.id;
has[id] = null;
watcher.run();
if (tempCloseCallUpdatedHooks) {
break;
}
// in dev build, check and stop circular updates.
if (process.env.NODE_ENV !== 'production' && has[id] != null) {
circular[id] = (circular[id] || 0) + 1;
if (circular[id] > MAX_UPDATE_COUNT) {
warn(
'You may have an infinite update loop ' + (
watcher.user
? ("in watcher with expression "" + (watcher.expression) + """)
: "in a component render function."
),
watcher.vm
);
break
}
}
}

// keep copies of post queues before resetting state
var activatedQueue = activatedChildren.slice();
var updatedQueue = queue.slice();

resetSchedulerState();

// call component updated and activated hooks
callActivatedHooks(activatedQueue);
if (!tempCloseCallUpdatedHooks) {
callUpdatedHooks(updatedQueue);
}
tempCloseCallUpdatedHooks = false

// devtool hook
/* istanbul ignore if */
if (devtools && config.devtools) {
devtools.emit('flush');
}
}`

3 node_modules\ant-design-vue\es\input\Input.js 找到watch 函数 增加 this.tempCloseCallUpdatedHooks()

完成以上性能问题解决,唯一的问题是 你的页面内 将无法使用 watch 来监听的 input 绑定的value
此问题我正在解决中。。。

@HanPengzhou
Copy link

HanPengzhou commented Mar 15, 2021

image

在2.0版本中,使用前值标签 需要根据前值标签中的值,来动态验证input的值,现在自定义验证器只能获取输入value,无法传入额外参数,所以不能进行验证.这个有前缀的input是动态的,所以无法用this.data里的值

image
而且提示位置不对

@zkwolf
Copy link
Member

zkwolf commented Mar 15, 2021

@HanPengzhou 单独开issue吧

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests