This is the 12th day of my participation in Gwen Challenge

preface

After writing an article about the unbeatable encapsulation of the request module in the field project last time, I put a serious problem affecting the user experience on the agenda.

You can work with me to improve the request module after reading the above article.

How to cancel Pomrise?

scenario

Left and right page layout, click the element in the task list on the left to obtain the task details on the right.

In this scenario, normal testing is fine, but frequent toggling and clicking on the left task list can create a serious experience problem.

Since the getTaskDetail function is run after clicking on the left, the logic is as follows.

  1. The details page on the right is displayedloading.
  2. Gets the filter criteria.
  3. Request the interface to get the ID or other value based on the clicked task.
  4. Get the data returned by the interface and assign it to the page variable.
  5. The details page on the right is closedloading.
async getTaskDetail() {
        this.rightLoading = true
        const httpObj: HttpObj = await this.checkHttpObj()
        const {
                data: { checklists, students },
                meta: { school_alias, checklist_form },
        } =fetch("task.detail", { school_id: this.activeSchoolId, ... httpObj })this.rightDetail = {
                checklists,
                students,
                school_alias,
                checklist_form,
        }
        this.rightLoading = false
    }
Copy the code

troubled

As shown in the preceding function, frequent clicking on the left will cause problems with detailed data and loading display/hiding, and waste requested network resources.

How do I cancel the first Get Promise when I click for details the second time?

How do I resolve the case where I cancel promises and process different aliases at the same time?

parsing

One way to think about it is that each requested interface alias is unique, and we need to know which alias is being requested and then cancel the requested Promise.

  1. Create a local object to store the requested objectPromise.
interface FetchHashMap = {
    [aclAlias: string] :Promise<Response>
}

fetchHashMap:FetchHashMap = {}

Copy the code
  1. Add a few functions to handle itA Promise for the alias interface is being requested.
hasFetchData(aclString: string) :boolean {
        return this.fetchHashMap[aclString] ? this.fetchHashMap[aclString] : false
}
deleteFetchData(aclString: string) {
        delete this.fetchHashMap[aclString]
}
setFetchData(aclString: string, promise: Promise<any>) {
        this.fetchHashMap[aclString] = promise

        return this.fetchHashMap[aclString]
}
Copy the code
  1. The following code is the request module encapsulated in the previous article. We are the first4Continue to improve.
/** * Simple encapsulation *@params {string} Route alias *@params {Object} Pass argument *@return Response* * /
async fetch(aclString: string, httpObj? :Object, paramsObj? :Object){...// Get the routing data according to the alias, then check whether there are routing parameters
    if (isHaveRouteParams) {
            ...
           
            if (paramsSuccess) {
                    const result = await fetchPost(aclString, routeHttpObj, method, postHttpObj, paramsObj)
                    return result
            } else {
                    console.error(routesArray)
                    console.error("Parameter passed in incomplete or parameter value is null.")}}else {
            // No routing parameters are requested directly
            const result = await fetchPost(aclString, {}, method, httpObj, paramsObj)
            return result
    }
}
Copy the code
  1. Put the final requestPromiseSeparate it out.
/** * reduce the same code, unified request interface *@param  {string} AclString Permission ACL *@param  {object} RouteHttpObj Route alias parameter *@param  {string} Method Request method *@param  {object} PostHttpObj Post parameter *@param  {object} ParamsHttpObj Route suffix parameter *@return {Promise<Response>} Result Return parameter **/ after the request interface
async fetchPost(aclString: string.routeHttpObj: any.method: string.postHttpObj: any.paramsHttpObj: any) :Promise<any> {
    let httpUrl: any = Object.keys(routeHttpObj).length ? await this.getApi(aclString, routeHttpObj) : await this.getApi(aclString)

    if (paramsHttpObj && Object.keys(paramsHttpObj).length) {
            const paramsUrl: string = this.getQueryObject(paramsHttpObj)
            httpUrl = `${httpUrl}?${paramsUrl}`
    }

    const result: any = this.fetchPostWrap(this.http[method](httpUrl, postHttpObj).toPromise())
    return result 
Copy the code
  1. Add logic to the requesting function.

    (1). The requested Promise is passed into the module.

    (2). Check whether the current request alias exists in fetchHashMap.

    (3). If there is a request for the same alias, we need to break its Promise.

    (4). If no request for the alias is pending, no request for the alias is pending.

    (5). Then process the current request and return a Promise as normal.

    (6). Delete the current request recorded in fetchHashMap before returning the result.


asyncfetchPost(...) :Promise<any> {...let abort, fetchPromise
        // Use promise.race to cancel the Promise
        // Race () returns a Promise that fails or succeeds, regardless of other promises
        const result: any = Promise.race([
                this.http[method](httpUrl, postHttpObj).toPromise(),
                new Promise((resolve, reject) = > {
                        abort = reject
                }),
        ])
        // Pull out the reject in race that cancels promises for subsequent calls
        result.abort = abort
        
        // When a request comes in, determine whether a request with a unique alias is being requested. If so, abort is run.
        if ((fetchPromise = this.hasFetchData(aclString))) {
                fetchPromise.abort({})
        }
        // Record the Promise of the current request
        fetchPromise = this.setFetchData(aclString, result)
        // Return the request result normally
        return fetchPromise
                .then((res) = > {
                        // When a request Promise is returned, the requested Promise is pushed out.
                        this.deleteFetchData(aclString)
                        return res
                })
                .catch((error) = > error)
}
Copy the code

Call it a day.

The last

Give me a thumbs up before I leave.

In addition to promote their own interview series, update

Interviewer: Do you know Callback Hell?

Interviewer: What’s the difference between react and Vue?

Interviewer: Do you know anything about ES6?

Interviewer: Do you know anything about Webpack?

Interviewer: Have you ever written a loader and separated modules while using WebPack?

Interviewer: How to correctly identify data types in Javascript?