【问题标题】:How to populate arrays efficiently and non blocking如何有效且非阻塞地填充数组
【发布时间】:2020-01-05 13:13:23
【问题描述】:

场景如下……

组件模板

<template>
  <div>
   <loader v-show="loading"></loader> // loading animation
   <div v-show="!loading">
     <div v-for="group in groups">
       {{group.name}}
       <div v-for="item in group.list">
         {{item.name}}
       </div>
     </div>
   </div>
  </div>
</template>

组件数据

data: function () {
    return {
        list: [],
        groups: [],
        loading: true
    }
}

1.从 api 获取一维数组

axios.get(API_URL).then(
    (response) => {
        this.list = response.data.payload;
    }
);

数组结构如下...

[
  {
    "name": "bob",
    "group": "A"
  },
  {
    "name": "sally",
    "group": "A"
  },
  {
    "name": "john",
    "group": "B"
  },
  {
    "name": "jane",
    "group": "B"
  },
]

2。使用每个项目的 group 属性将数组转换为二维

当前解决方案(阻塞!效率低下?

// loading animation stops at this point
this.list.forEach((item, index) => {
    let hasGroupChanged = false;
    if (index === 0) {
        hasGroupChanged = true;
    } else {
        let currentGroupName = item.group;
        let previousGroupName = this.list[index - 1].group;
        hasGroupChanged = previousGroupName !== currentGroupName;
    }
    if (hasGroupChanged) {
        const group = {
            group: item.group,
            list: []
        };
        this.groups.push(group);
    }
    const groupIndex = this.groups.length - 1;
    this.groups[groupIndex].list.push(item);
});

this.loading = false;

在填充组之前如何保持加载动画?

【问题讨论】:

  • 您想要一种有效地填充数组的方法,还是要确保加载动画在您加载数据之前一直运行?您当前的解决方案是否使加载动画持续到最后?是什么让您当前的解决方案受阻?

标签: javascript arrays vue.js async-await


【解决方案1】:

您的“加载”动画被“冻结”,因为 JavaScript 是单线程的,并且当您的转换代码运行时(假设数据比示例中显示的多得多,因此它运行了很长时间),浏览器的渲染被屏蔽了。

您可以优化转换代码以使其更快,或者您可以查看this SO answer 了解如何使长时间运行的操作不阻塞浏览器渲染的详细信息和解决方案......

【讨论】:

    【解决方案2】:

    我猜问题是您在 axios 完成获取数据之前将 loading 设置为 false(因为这是代码中唯一的异步操作)。

    .forEach 可能会稍微优化一下,但我怀疑这是罪魁祸首。

    尝试将.then 中的所有代码从axios.get() 链接下来。

    【讨论】:

      【解决方案3】:

      我不能真正谈论您的代码的效率,但是保持加载指示器持续到异步操作完成后的一种简单方法是在 finally-block 中停止它:

      const btn = document.getElementById('btn');
      const mockLoadIndicator = document.getElementById('loading');
      const data = [
        {
          "name": "bob",
          "group": "A"
        }, {
          "name": "sally",
          "group": "A"
        }, {
          "name": "john",
          "group": "B"
        }, {
          "name": "jane",
          "group": "B"
        }
      ];
      const mockAPI = () => {
        mockLoadIndicator.style.display = 'block';
        return new Promise((resolve) => {
          setTimeout(() => resolve(data), 1000);
        });
      };
      
      btn.onclick = () => mockAPI()
      .then(console.log)
      .finally(() => {
        mockLoadIndicator.style.display = 'none';
      });
      #loading {
        position: relative;
        display: none;
        height: 10px;
        width: 10px;
        border-radius: 50%;
        background: grey;
        animation-duration: 300ms;
        animation-name: load;
        animation-iteration-count: infinite;
        animation-direction: alternate;
      }
      
      @keyframes load {
        from {
          left: 10px;
        }
        to {
          left: 40px;
        }
      }
      <button id="btn">Get Data</button>
      <div id="loading"></div>

      【讨论】:

        猜你喜欢
        • 2014-09-21
        • 2021-06-24
        • 2013-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-24
        相关资源
        最近更新 更多