Scenario

In the actual business development, there are often some tasks that need to be executed for a long time, so there are two problems:

  • Frontend: How to realize the display and step of progress bar?
  • Backend: If the backend takes too long to execute, the frontend will receive a timeout error. How to avoid it?

Module a-progress easily solves the above problems, and has the following characteristics:

  • Convenient API
  • Support multi-level progress bar

Preview

progress-bar-en-us

Frontend

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. Firstly, perform backend API route to get progressId
  2. Then invoke $view.dialog.progressBar to display the progress bar. This function automatically gets the latest progress from the backend and updates the display

Backend - API Route

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 } } },

Backend - Controller

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;
};

Three levels of progress bar are implemented here, and for the sake of intuitiveness, the common code of these three levels is not refined into a common function. In the actual development, it can be simplified according to the actual needs

Description of Process

  • Method: progress

    1. invoke ctx.meta.progress.create to create a progressId
    2. invoke ctx.performActionInBackground to start the task as the background mode
    3. return progressId to the frontend for displaying the progress bar
  • Method: progressInBackground

    1. Use try/catch structure to wrap code, so as to catch code exceptions and update the status of progress bar
    2. invoke ctx.meta.progress.update to update the progress
    3. invoke ctx.meta.progress.done to complete the progress
    4. invoke ctx.meta.progress.error to raise error message

Description of API

  • Method: ctx.meta.progress.update
Name Description
progressId progress Id
progressNo the level index, start from 0
total the total tasks of current level
progress the task index of current level, start from 0
text description of the current task
  • Method: ctx.meta.progress.done
Name Description
progressId progress Id
message description on completion
  • Method: ctx.meta.progress.error
Name Description
progressId progress Id
message error description