Meteor / Blaze:用最少的重绘更新列表属性
Meteor / Blaze: updating list properties with minimal redraw
我遇到了与 Blaze 重绘相关的严重性能问题。我知道我的数据结构有问题,但我找不到修复它的方法。这一篇有点长,我会尽力把它排清楚。
目标/问题
我想创建一个日程视图,用户可以在其中安排测试。用户应该可以拖放测试槽,但重绘速度太慢,无法使用。
数据
我有一个 Sittings
集合,用于存储有关测试时间的详细信息。每次考试都有一个 scheduleGroups
的列表(即 exam1 和 exam2 发生在星期二,exam3 和 exam4 发生在星期三)结构看起来大致像这样:
var sitting = {
"_id" : "sittingId",
"name" : "Amazing Sitting",
"locationIds" : [
"room1_id",
"room2_id"
],
"startDate" : ISODate("2015-07-01T04:00:00Z"),
"endDate" : ISODate("2015-07-02T04:00:00Z"),
"scheduleGroups" : [
{
"_id" : "dEb3mC7H8RukAgPG3",
"name" : "New group",
"booths" : [
{
"boothNumber" : 1,
"slots" : [
{
"examId" : "exam1",
"dayNumber" : 1,
"startTime" : {
"hour" : 8,
"minutes" : 0
},
"endTime" : {
"hour" : 9,
"minutes" : 30
},
"candidateId" : "odubbD42kHDcR8Egc",
"examinerIds" : [
"GQmvyXbcmMckeNKmB",
"GfoBy4BeQHFYNyowG"
]
}
]
}
]
"locationId" : "room1_id"
}],
"examIds" : [
"exam1",
"exam2",
"exam3"
]
};
HTML
Sitting 在 Router.current().data
钩子中被定义为全局上下文。这是重绘问题的一部分。无论如何,下面的 HTML 会产生以下布局(下面的 img)。
<template name='scheduler'>
<div class='container'>
<div class='tabpanel'>
<div class='tab-content' id='scheduler-content'>
{{#each getScheduleGroups}}
<div class='container-fluid schedule-wrapper'>
<div class='row'>
<div class='scheduler-inner-box placeholder-box'></div>
{{#each booths}}
<div class='group-column-head scheduler-inner-box'>{{boothNumber}}</div>
{{/each}}
</div>
<!-- Sittings can take place over several days, normally 2 days -->
{{#each sittingDays}}
<div class='day-wrapper'>
<h3 class='text-center'>Day {{this}}</h3>
<!-- This helper returns a list of start times: [June 1 9AM, June 1 915AM....] -->
{{#each getScheduleTimes ..}}
<div class='row time-row'>
<div class='group-row-head scheduler-inner-box'>
<span class='box-content'>{{this}}</span>
</div>
<!-- Loop through each booth, so that each slot has a square for that boot
i.e. June 1 9AM has space for booth 1, and booth 2, and booth 3, etc
-->
{{#each ../../booths}}
<!-- Paper starting now tells us if there is a slot scheduled to begin at this time or wher its empty-->
<div class='scheduler-inner-box {{#unless paperStartingNow ../.. ..}}open-booth{{/unless}}'>
{{#with paperStartingNow ../.. .. boothNumber}}
<!--
getSlotStyle calculates height and colour, depending on how long the paper is and whether
it's ready to go: i.e. does it have a candidate and the right number of examiners?
-->
<div class='paper-tile tile' {{getSlotStyle this ../boothNumber 'paper'}}>
<span class='slot-name'>{{getSlotName}}</span>
</div>
{{#if slotHasCandidate}}
<div class='candidate-tile tile' {{getSlotStyle this ../boothNumber 'candidate'}}>
<span class='slot-name candidate-name'>{{getCandidateDisplay}}</span>
</div>
{{/if}}
{{#each slotExaminers}}
<div class='examiner-tile tile' {{getSlotStyle .. ../../boothNumber 'examiner' index}}>
<span class='slot-name examiner-name'>{{profile.name}}</span>
</div>
{{/each}}
{{/with}}
</div>
{{/each}}
</div>
{{/each}}
</div>
{{/each}}
</div>
{{/each}}
</div>
</div>
</div>
问题
当用户将插槽(紫色方块)放到空 space 上,或将考生或考官拖到另一个方块时,我会更新集合并让 Meteor 重绘。然而,整个事情都重绘了,我找不到隔离的方法。
这是移动整个插槽的代码,考生考官和所有。
moveSlot: function (originalBoothNumber, originalSlot, dropBoothNumber, newSlot) {
check( originalBoothNumber, Number );
check( originalSlot, Object );
check( dropBoothNumber, Number );
check( newSlot, Object );
//pull the old slot
var originalBooth = _.findWhere( this.booths, {boothNumber: originalBoothNumber} );
originalBooth.slots = _.without( originalBooth.slots, originalSlot );
//insert the new one
var dropBooth = _.findWhere( this.booths, {boothNumber: dropBoothNumber} );
dropBooth.slots.push( newSlot );
var modifier = {
$set: {}
};
modifier["$set"]["scheduleGroups." + this.getIndex() + ".booths"] = this.booths;
return Sittings.update({_id: this.getSitting()._id }, modifier);
},
我需要改变我的存储方式吗Sitting.booths
?如果有人能推荐一个更好的数据结构,它只会触发重绘槽,我'我真的很感激。我发现了一个将每个插槽放入会话变量的技巧,但必须有另一种方法。
感谢您的耐心等待和帮助,
分贝
问题
因为你把slots
整套存储在了booth
的一个文档中。更新 slot
后,整个文档都被视为已更新。
解决方案
恕我直言,我认为您不需要更改结构,除非 您已经构建了搜索 slot
或 booth
的功能。您可以通过创建一系列 reactiveVariable
或 reactiveDictionary
来设置它,您的模板应该仅取决于该反应变量。每次更新时,请考虑手动或自动在其中两个之间进行同步。
PS. 我没有与此站点建立任何附属关系:https://www.sportsplus.me。但是如果你注册 -> 主页 -> mlb -> anycontest -> 点击加号,你可以看到他们的杰作 infinite scroll with partially redraw。 (打开您的开发控制台并观察元素的变化)。他们做的事情与您尝试做的事情完全相同,只需要最少的重绘。
我遇到了与 Blaze 重绘相关的严重性能问题。我知道我的数据结构有问题,但我找不到修复它的方法。这一篇有点长,我会尽力把它排清楚。
目标/问题
我想创建一个日程视图,用户可以在其中安排测试。用户应该可以拖放测试槽,但重绘速度太慢,无法使用。
数据
我有一个 Sittings
集合,用于存储有关测试时间的详细信息。每次考试都有一个 scheduleGroups
的列表(即 exam1 和 exam2 发生在星期二,exam3 和 exam4 发生在星期三)结构看起来大致像这样:
var sitting = {
"_id" : "sittingId",
"name" : "Amazing Sitting",
"locationIds" : [
"room1_id",
"room2_id"
],
"startDate" : ISODate("2015-07-01T04:00:00Z"),
"endDate" : ISODate("2015-07-02T04:00:00Z"),
"scheduleGroups" : [
{
"_id" : "dEb3mC7H8RukAgPG3",
"name" : "New group",
"booths" : [
{
"boothNumber" : 1,
"slots" : [
{
"examId" : "exam1",
"dayNumber" : 1,
"startTime" : {
"hour" : 8,
"minutes" : 0
},
"endTime" : {
"hour" : 9,
"minutes" : 30
},
"candidateId" : "odubbD42kHDcR8Egc",
"examinerIds" : [
"GQmvyXbcmMckeNKmB",
"GfoBy4BeQHFYNyowG"
]
}
]
}
]
"locationId" : "room1_id"
}],
"examIds" : [
"exam1",
"exam2",
"exam3"
]
};
HTML
Sitting 在 Router.current().data
钩子中被定义为全局上下文。这是重绘问题的一部分。无论如何,下面的 HTML 会产生以下布局(下面的 img)。
<template name='scheduler'>
<div class='container'>
<div class='tabpanel'>
<div class='tab-content' id='scheduler-content'>
{{#each getScheduleGroups}}
<div class='container-fluid schedule-wrapper'>
<div class='row'>
<div class='scheduler-inner-box placeholder-box'></div>
{{#each booths}}
<div class='group-column-head scheduler-inner-box'>{{boothNumber}}</div>
{{/each}}
</div>
<!-- Sittings can take place over several days, normally 2 days -->
{{#each sittingDays}}
<div class='day-wrapper'>
<h3 class='text-center'>Day {{this}}</h3>
<!-- This helper returns a list of start times: [June 1 9AM, June 1 915AM....] -->
{{#each getScheduleTimes ..}}
<div class='row time-row'>
<div class='group-row-head scheduler-inner-box'>
<span class='box-content'>{{this}}</span>
</div>
<!-- Loop through each booth, so that each slot has a square for that boot
i.e. June 1 9AM has space for booth 1, and booth 2, and booth 3, etc
-->
{{#each ../../booths}}
<!-- Paper starting now tells us if there is a slot scheduled to begin at this time or wher its empty-->
<div class='scheduler-inner-box {{#unless paperStartingNow ../.. ..}}open-booth{{/unless}}'>
{{#with paperStartingNow ../.. .. boothNumber}}
<!--
getSlotStyle calculates height and colour, depending on how long the paper is and whether
it's ready to go: i.e. does it have a candidate and the right number of examiners?
-->
<div class='paper-tile tile' {{getSlotStyle this ../boothNumber 'paper'}}>
<span class='slot-name'>{{getSlotName}}</span>
</div>
{{#if slotHasCandidate}}
<div class='candidate-tile tile' {{getSlotStyle this ../boothNumber 'candidate'}}>
<span class='slot-name candidate-name'>{{getCandidateDisplay}}</span>
</div>
{{/if}}
{{#each slotExaminers}}
<div class='examiner-tile tile' {{getSlotStyle .. ../../boothNumber 'examiner' index}}>
<span class='slot-name examiner-name'>{{profile.name}}</span>
</div>
{{/each}}
{{/with}}
</div>
{{/each}}
</div>
{{/each}}
</div>
{{/each}}
</div>
{{/each}}
</div>
</div>
</div>
问题 当用户将插槽(紫色方块)放到空 space 上,或将考生或考官拖到另一个方块时,我会更新集合并让 Meteor 重绘。然而,整个事情都重绘了,我找不到隔离的方法。
这是移动整个插槽的代码,考生考官和所有。
moveSlot: function (originalBoothNumber, originalSlot, dropBoothNumber, newSlot) {
check( originalBoothNumber, Number );
check( originalSlot, Object );
check( dropBoothNumber, Number );
check( newSlot, Object );
//pull the old slot
var originalBooth = _.findWhere( this.booths, {boothNumber: originalBoothNumber} );
originalBooth.slots = _.without( originalBooth.slots, originalSlot );
//insert the new one
var dropBooth = _.findWhere( this.booths, {boothNumber: dropBoothNumber} );
dropBooth.slots.push( newSlot );
var modifier = {
$set: {}
};
modifier["$set"]["scheduleGroups." + this.getIndex() + ".booths"] = this.booths;
return Sittings.update({_id: this.getSitting()._id }, modifier);
},
我需要改变我的存储方式吗Sitting.booths
?如果有人能推荐一个更好的数据结构,它只会触发重绘槽,我'我真的很感激。我发现了一个将每个插槽放入会话变量的技巧,但必须有另一种方法。
感谢您的耐心等待和帮助, 分贝
问题
因为你把slots
整套存储在了booth
的一个文档中。更新 slot
后,整个文档都被视为已更新。
解决方案
恕我直言,我认为您不需要更改结构,除非 您已经构建了搜索 slot
或 booth
的功能。您可以通过创建一系列 reactiveVariable
或 reactiveDictionary
来设置它,您的模板应该仅取决于该反应变量。每次更新时,请考虑手动或自动在其中两个之间进行同步。
PS. 我没有与此站点建立任何附属关系:https://www.sportsplus.me。但是如果你注册 -> 主页 -> mlb -> anycontest -> 点击加号,你可以看到他们的杰作 infinite scroll with partially redraw。 (打开您的开发控制台并观察元素的变化)。他们做的事情与您尝试做的事情完全相同,只需要最少的重绘。