Javascript是單線程的,還會湧現數據合作嗎?當然會!

斟酌以下代碼

whatever.onclick = async () => {
    const a = await(await fetch('step-1')).text();
    const b = await(await fetch('step-2')).text();
    whatever.textContent = a + b;
}

假如用戶在step-1step-2之間再次點擊的話,就有能夠同時發出兩個step-1

固然,服務器能夠考證以後統統拒掉,然則用戶體驗很差。這是個很合理的需求,所以我特意在SF上發問,惋惜看起來並沒有現成的輪子能夠用。

所以照樣只能本身造。

用下面的函數包裹原函數,假如前一次要求還沒有完畢,新要求會和舊要求一同返回。

/**
 * Creates a function that invokes `originalFunction`, with the `this` binding
 * and `arguments` of the created function, while there is no other pending 
 * excutions of `originalFunction`. Simultaneous calls to the created function
 * return the result of the first pending `originalFunction` invocation.
 * 
 * @param {function} originalFunction async function to wrap
 */
const debounceAsync = originalFunction => {
    let currentExcution = null;
    const wrappedFunction = async function () {
        // 1. locked => return lock
        if (currentExcution) return currentExcution;

        // 2. released => apply
        currentExcution = originalFunction.apply(this, arguments);
        try {
            return await currentExcution;
        }
        finally {
            currentExcution = null;
        }
    };
    return wrappedFunction;
};

用下面的函數包裹原函數,假如前一次要求還沒有完畢,新要求會列隊。

const endOfQueue = Promise.resolve();
const overrideResult = async lastExcution => {
    try {
        await lastExcution;
    }
    finally {
        return endOfQueue;
    }
}

/**
 * Creates a function that invokes `originalFunction`, with the `this` binding
 * and `arguments` of the created function, while there is no other pending 
 * excutions of `originalFunction`. Simultaneous calls to the created function
 * will be queued up.
 * 
 * @param {function} originalFunction async function to wrap
 */
const queueAsync = originalFunction => {
    let lastExcution = endOfQueue;
    const wrappedFunction = async function () {
        // 1. queue up
        const myExcution = lastExcution.then(() => originalFunction.apply(this, arguments));

        // 2. update queue tail + swipe excution result from queue
        lastExcution = overrideResult(myExcution);

        // 3. return excution result
        return myExcution;
    };
    return wrappedFunction;
}

示例運用

/**
 * A promisified settimeout
 * 
 * @param {number} [ms=0] time to sleep in ms
 */
const sleep = (ms = 0) => new Promise(resolve => setTimeout(resolve, ms));

const debounceAsync_UNIT_TEST = async () => {
    const goodnight = debounceAsync(sleep);
    for (let i = 0; i < 8; i++) {
        goodnight(5000).then(() => console.log(Date()));
        await sleep(500);
    }
    console.warn('Expected output: 8 identical datetime');
};

const queueAsync_UNIT_TEST = () => {
    const badnight = queueAsync(i => sleep(i).then(() => { if (Math.random() > 0.5) throw new Error('uncaught error test: you should expect a console error message.') }));
    badnight(1000);
    badnight(1000);
    badnight(1000);
    badnight(1000);
    badnight(1000).finally(() => console.log('5s!'));
    badnight(1000);
    badnight(1000);
    badnight(1000);
    badnight(1000);
    badnight(1000).finally(() => console.log('10s!'));
    console.warn('Check message timestamps.');
    console.warn('Bad:');
    console.warn('1 1 1 1 1:5s');
    console.warn(' 1 1 1 1 1:10s');
    console.warn('Good:');
    console.warn('1 1 1 1 1:5s');
    console.warn('         1 1 1 1 1:10s');
}

以上一切代碼按Mozilla Public License, v. 2.0受權。
以上一切筆墨內容按CC BY-NC-ND 4.0受權。

    原文作者:liqi0816
    原文地址: https://segmentfault.com/a/1190000015289829
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞