应用场景

在实际业务开发当中,经常有一些任务需要执行比较长的时间,那么就出现了两个问题:

  • 前端:如何实现进度条的显示步进
  • 后端:如果后端执行时间过长,前端就会收到超时错误。如何避免?

CabloyJS内置模块a-progress轻松化解了上述问题,而且具有以下特点:

  • 便捷的Api调用
  • 支持层级显示

效果演示

progressbar.2019-07-21 20_57_06

前端调用

src/module/test-party/front/src/kitchen-sink/pages/progress.vue

onPerformStart() {
  return new Promise((resolve, reject) => {
    return this.$api.post('test/feat/progress').then(data => {
      const progressId = data.progressId;
      this.$view.dialog.progressbar({ progressId, title: this.$text('Working') }).then(data => {
        console.log(data);
        resolve();
      }).catch(err => {
        console.log(err);
        reject();
      });
    });
  });
},
  1. 先调用后端Api取得progressId
  2. 调用$view.dialog.progressbar显示进度条即可。此函数内部会自动从后端获取最新进度并更新显示

后端Api路由

src/module/test-party/backend/src/routes.js

// test/feat/progress
{ method: 'post', path: 'test/feat/progress', controller: testFeatProgress, middlewares: 'progress', meta: { auth: { enable: false } } },
{ method: 'post', path: 'test/feat/progressInBackground', controller: testFeatProgress, middlewares: 'inner,progress', meta: { auth: { enable: false } } },

后端Api控制器

src/module/test-party/backend/src/controller/test/feat/progress.js

module.exports = app => {

  class ProgressController extends app.Controller {

    async progress() {
      // create progress
      const progressId = await this.ctx.meta.progress.create();
      // background
      this.ctx.performActionInBackground({
        method: 'post',
        url: 'test/feat/progressInBackground',
        body: {
          progressId,
        },
      });
      // return progressId
      this.ctx.success({ progressId });
    }

    async progressInBackground() {
      const progressId = this.ctx.request.body.progressId;
      try {
        // level one
        await this._levelOne({ progressId, progressNo: 0 });
        // progress done
        await this.ctx.meta.progress.done({ progressId, message: this.ctx.text('Well Done') });
        // ok
        this.ctx.success(true);
      } catch (err) {
        // progress error
        await this.ctx.meta.progress.error({ progressId, message: err.message });
        // throw err
        throw err;
      }
    }

    async _levelOne({ progressId, progressNo }) {
      const total = 2;
      let current = 0;
      for (let i = 0; i < total; i++) {
        const text = `${this.ctx.text('Level One')}: ${i + 1}`;
        await this.ctx.meta.progress.update({
          progressId,
          progressNo,
          total,
          progress: current++,
          text,
        });
        // sleep
        await this.ctx.meta.util.sleep(1500);
        // level two
        await this._levelTwo({ progressId, progressNo: progressNo + 1 });
      }
    }

    async _levelTwo({ progressId, progressNo }) {
      const total = 2;
      let current = 0;
      for (let i = 0; i < total; i++) {
        const text = `${this.ctx.text('Level Two')}: ${i + 1}`;
        await this.ctx.meta.progress.update({
          progressId,
          progressNo,
          total,
          progress: current++,
          text,
        });
        // sleep
        await this.ctx.meta.util.sleep(1500);
        // level two
        await this._levelThree({ progressId, progressNo: progressNo + 1 });
      }
    }

    async _levelThree({ progressId, progressNo }) {
      const total = 3;
      let current = 0;
      for (let i = 0; i < total; i++) {
        const text = `${this.ctx.text('Level Three')}: ${i + 1}`;
        await this.ctx.meta.progress.update({
          progressId,
          progressNo,
          total,
          progress: current++,
          text,
        });
        // sleep
        await this.ctx.meta.util.sleep(1500);
      }
    }

  }
  return ProgressController;
};

在这里实现了三个层级的进度条,而且为了直观性,这三个层级的代码直接展开(没有将共性代码提炼成公共函数) 。在实际开发中可以根据实际需要进行简化

流程说明

  • 方法progress

    1. 调用ctx.meta.progress.create生成一个progressId
    2. 调用ctx.performActionInBackground,以便在后台启动任务。如果直接在这里执行任务,时间过长会导致前端收到超时错误
    3. 向前端返回progressId,从而显示进度条
  • 方法progressInBackground

    1. 使用try/catch结构包裹代码,便于捕获代码异常,更新进度条的状态
    2. 调用ctx.meta.progress.update更新进度
    3. 调用ctx.meta.progress.done完成进度
    4. 调用ctx.meta.progress.error登记错误信息

Api说明

  • 方法ctx.meta.progress.update
名称 说明
progressId 进度标识
progressNo 当前进度层级编号,从0开始
total 当前层级的任务总数
progress 当前层级的当前任务进度,从0开始
text 当前层级的当前任务进度的描述信息
  • 方法ctx.meta.progress.done
名称 说明
progressId 进度标识
message 完成之后的提示信息
  • 方法ctx.meta.progress.error
名称 说明
progressId 进度标识
message 错误信息