Source

lock.js

import {awaitPromiseRes} from "./async.js";
import {noop} from "./other.js";

/**
 * @description lock user actions until it finished
 * @example
 * //创建
 * import { getTriggerLock } from '@/utils/lock.js';
 * let locker = getTriggerLock();
 * export default {
 *      onLoad(){
 *          locker.release();
 *      },
 *      methods:{
 *          onClickToProductDetail(){
 *            locker.trigger(async () => {
 *              let res1 = await getDataByAjax();
 *              let res2 = await setCartItem();
 *              let id = res2.data.data.id;
 *              uni.navigateTo({
 *                url: "/pages/somePage?id="+id
 *              })
 *            });
 *          }
 *      }
 *  });
 *
 */
export class TriggerLock {
    constructor() {
        this.locking = false;
    }
    async trigger(handler) {
        if (this.locking) {
            return;
        }

        this.locking = true;
        let res = null;

        try {
            this.locking = true;

            try {
                res = handler(); //如果返回的是一个promise,那么自动在最后进行解锁
                if (res instanceof Promise) {
                    await res;
                }
            } finally {
                this.locking = false;
            }
        } catch (e) {
            console.error('trigger err', e);
            this.release();
        }
    }
    release() {
        this.locking = false;
    }

    isLocking() {
        return this.locking;
    }

    static getInstance() {
        return new TriggerLock();
    }

    wrap(func) {
        return LockerWrapper(this, func);
    }
}

/**
 * @description get lockFactory instance of click action
 * @returns {TriggerLock}
 */
export function getTriggerLock(){
    return TriggerLock.getInstance(...arguments);
}

/**
 * @description create function with locker
 * @param {TriggerLock} locker a instance of TriggerLocker
 * @param {function} func you would like to control the function through locker, the default value is empty function, just like noop
 * @returns {function}
 */
export function LockerWrapper (locker, func = noop) {
    if (!locker) {
        console.log('please pass locker');
        return func;
    }

    if (!(locker instanceof TriggerLock)) {
        console.error('please pass instance of TriggerLock');
        return func;
    }

    return async function (...args) {
        return await locker.trigger(async () => {
            let res = func.apply(this, args);
            return await awaitPromiseRes(res);
        });
    };
}