preface

ES6 has greatly improved our programming experience. Besides simply waiting for the results of calling links with await, we can also improve our programming experience by using certain skills

Promise’s Sleep technology

In ES5, we often use setTimeout to do deferred sleep and add a callback hook to handle the delayed action. For example, if the dialog box appears 2 seconds after clicking a button, we can write something like this

// <button onclick="handleclick()"></button>

function handleclick(){
    setTimeout(() = >{
        openDialog();
    });
}

function openDialog(){
    // Handle the pop-up and the interactive logic behind the pop-up
}
Copy the code

The code has a lot of callback hooks that are not very intuitive, and we can use promises to solve this problem

// <button onclick="handleclick()"></button>

async function sleep(ms){
    return new Promise(resolve= >{
        setTimeout(resolve, ms);
    });

    Const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
}

async function handleclick(){
    await sleep(2000); 
    // Handle the pop-up and the interactive logic behind the pop-up
}

Copy the code

Caching HTTP results

Let’s say we have an API /member interface. We want the interface data to be cached so that when the application is called in multiple places, the request will not be sent repeatedly

let CACHE_MEMBER_INFO = undefined;
export default async function getMemberInfo(){
    if(CACHE_MEMBER_INFO){
        return CACHE_MEMBER_INFO;
    }

    CACHE_MEMBER_INFO = await ajax.get('api/member');
    return CACHE_MEMBER_INFO;
}
Copy the code

The above code doesn’t look too bad. But since ajax.get is asynchronous, that means that if you make two getMemberInfo() calls at the same time, you’ll still make two Ajax requests, which is obviously redundant. We want to only have one ajax request at a time. If we have multiple requests, You should reuse this Ajax and wait for the results.

You should reuse this' ajax 'and wait for the resultsCopy the code

The purpose is not to cache MEMBER_INFO but AJAX(Promise), so the above code should be changed

let CACHE_MEMBER_INFO = undefined;
export default async function getMemberInfo(){
    if(CACHE_MEMBER_INFO){
        return CACHE_MEMBER_INFO;
    }

    CACHE_MEMBER_INFO = ajax.get('api/member');
    return CACHE_MEMBER_INFO;
}
Copy the code

Note that we remove the await and return ajax.get directly. This means that we don’t need to wait inside the function for the result of the returned value, but instead cache the entire call back. This can be tested with the following code

let count = 0;
const ajax = {
    // Return after two seconds
    async get(){
        await new Promise(resolve= > setTimeout(resolve, 2000));
        return++count; }}let CACHE_MEMBER_INFO = undefined;
async function getMemberInfo(){
    if(CACHE_MEMBER_INFO){
        return CACHE_MEMBER_INFO;
    }

    CACHE_MEMBER_INFO = ajax.get('api/member');
    return CACHE_MEMBER_INFO;
}


;(async() = > {console.info(new Date(), awaitgetMemberInfo()); }) (); ; (async() = > {console.info(new Date(), await getMemberInfo());
    await new Promise(resolve= > setTimeout(resolve, 5000));
    console.info(new Date(), awaitgetMemberInfo()); }) ();// Sat Aug 07 2021 12:55:09 GMT+0800
// VM107:28 Sat Aug 07 2021 12:55:09 GMT+0800 vm107:28 Sat Aug 07 2021 12:55:09 GMT+0800
// VM107:30 Sat Aug 07 2021 12:55:16 GMT+0800. Vm107:30 Sat Aug 07 2021 12:55:16 GMT+0800
Copy the code

The two closures are simulated calling at the same time. As you can see, the print time is exactly the same and the print results are the same, which means that ajax.get is executed only once, which is very handy to use! The above code can also be changed

let CACHE_MEMBER_INFO = undefined;
async function getMemberInfo(){
    // The assignment statement returns itself, equivalent
    // a = 1;
    // return a;
    / / equivalent to the
    // return a = 1;
    return CACHE_MEMBER_INFO = CACHE_MEMBER_INFO || ajax.get('api/member')
        .catch(err= >{
            CACHE_MEMBER_INFO = undefined; // The error message is not cached, but still needs to be sent to the outside
            throw err;
        });
}
Copy the code

So let’s go a little further and wrap the cache as a higher-order method

type fn = (. args:any) = > Promise<any>;
function cachePromiseResult(PromiseFn: fn) {
    let cache = undefined;
    return function (. args) {
        return (cache =
            cache ||
            PromiseFn.apply(this, args).catch((error) = > {
                cache = undefined;
                return Promise.reject(error);
            }));
    };
}

const getMemberInfo = cachePromiseResult(async function(){
    return ajax.get('api/member');
});
Copy the code

The cachePromiseResult cache the result of this function, and does not cache exceptions. Just write the process of calling the function as usual. So easy! In this case, this method can be applied anywhere you want. Note that promises are cached, meaning that the result of any asynchronous action can be cached, such as

const init = cachePromiseResult(async function(){
    showLoading();
    await sleep(2000);
    hideLoading();

    // The product asks him to wait two seconds for initialization
    return 'Initialization succeeded'
});
Copy the code

All right, it’s time to go get some BBS!