The introduction

Recently, in an internal wechat H5 project of the company, when developing a relatively common function (to obtain the user’s openId under the active public account), a “strange and unknown phenomenon “(my Chen-dong fan, haha) appeared. Before introducing this quirkiness, let’s briefly introduce the implementation process of this feature:

According to the webpage OAuth2.0 authentication specification in the development document of wechat public platform, H5 needs to be redirected to the specified page first, then redirected back to get the authorization code, and then sent to the server to communicate with wechat public platform to get openId.

The problem is redirection. The code for this page can be as simple as:

    let authCode
    function getAuthCode () {
        if{authCode = getUrlSearchParams('code')}else{location.replace method redirects}}function getOpenId () } getAuthCode() getOpenId()Copy the code

The result that the developers expected at the time was that if the getAuthCode method was executed to a page redirect, it would abort the subsequent getOpenId stack execution and redirect directly. However, the actual situation is that before the redirect, the getOpenId method is still executed, so the back end initiates the interface request, but the back end sets the code as a mandatory parameter, so with the front-end error processing in AXIos response interception, the error message pops up to the user.

Check if authCode has a value before executing inside the getOpenId method. But the phenomenon is very curious, with this curiosity we go to explore the specific reasons

explore

Step 1: Demo building experiment

Let’s take a look at the redirection in detail with some simple demos and effects videos

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta  name="viewport" content="width=device-width, Initial =1.0"> <title>Document</title> </head> <body> <script> function a () {location.href = 'https://www.baidu.com' } a() alert(1) </script> </body> </html>Copy the code

summary

Without the introduction, we might expect to jump directly to another page, with subsequent blocks of code not executing, and the actual result in Chrome popping up before jumping to another page

Why Chrome? Because the x5 browser kernel used by wechat App is non-open source, but it is adjusted based on WebKit. In order to avoid major adjustments to the redirection made by X5, we can compare the phenomenon between Chrome and wechat with the demo above, and find that they are consistent. So we can explore the Webkit source code in step 3

Chrome effect. Mp4

The second step: Baidu search

Results as we said in the introduction, the first step of our exploration is to go to Baidu, ha ha ha, to see if there is an article answer. After searching for some articles. The answer is divided into two parts:

  • No subsequent code execution occurs
  • Because page jumps are performed asynchronously

Answer must have two groups are not relate to, for the first answer, we are ruled out these people do not have manual experiment of the extremes, so why they won’t appear the follow-on code, we put focus on the browser engine differences, speculation is using different engines, take our Chrome experiments above, for example, The engines are WebKit and WebKit-based Blink. Let’s take another firefox Gecko kernel test.

Firefox effects mp4

As you can see from the video, firefox will still perform pop-up alert, but unlike Chrome, popovers don’t block the jump until you manually click. I then tried Internet Explorer, but alert was executed. Therefore, for the first part of the answer, Google, Firefox and Internet Explorer tested will execute the code after the jump. If other friends can indeed detect that they will not execute the following code, please leave a message with the browser kernel and version number

summary

Baidu after learning, we had a preliminary conclusion, redirect performance form is asynchronous, so everybody is thinking a question, asynchronous, that after we execute a jump how long is the code that will truly jump, is a fixed delay or performed all of the synchronized code block, or under the current macro task of all tasks. You can write a demo and test it, but to really understand the internals, we’ll look at the WebKit engine source code.

Step 3: WebKit source code analysis:

You can download Webkit from GitHub source code, friendly tips, content 10G. Please download it in advance. We will not discuss the directory structure and other content, interested students can go to see the relevant source code analysis, we only analyze the page jump code in this chapter. Also be involved in different development the syntax of the language differences, we can at the same time of reading, the c + + syntax next to a tutorial on the www.runoob.com/cplusplus/c…

  1. The location.href used belongs to the window object method, so we need to find the window creation file webkit\ webkit\ Source\WebCore\page\ domwindow.cpp. Skip to line 760 to see that the Location instance was created

  1. The Location module file is in webkit\ webkit\ Source\WebCore\page\ location. CPP. We’re jumping by assigning to location.href, internally using the setHref method. The line of code highlighted in the following figure is syntactically summarized as a return to the setLocation method call under the DOMWindow object we mentioned above

  1. Going back to line 2378 of the domwindow.cpp file, we’re just looking at the general process execution at the end. Careful friends get a sniff of the schedule on the method name scheduleLocationChange

  1. NavigationScheduler is in the WebKit Source WebCore loader navigationScheduler. CPP file on line 444. Let’s skip the middle case and see to the end

  1. By searching schedule for the current file, you can see the internal implementation of the method. There is a point in the middle that you can pay more attention to. If a redirection is scheduled during page reloading, stop the current load. The startTimer method at the bottom officially tells us that there is a timer!!

  1. If it’s a timer, how long will it delay? Looking at the most critical piece of code, the delay is dependent on 1s* the background of the current behavior to be redirected. As for the detailed classification of this behavioral background we will try to enumerate in later chapters.

summary

The typical redirection delay is near the base 1s

Step 4: Verify the results of the previous step

So how do we verify that? Let’s go back to the demo, and the core of the demo is that after you execute the jump code, you record the timestamp, and then you iterate over and over and over again, updating the latest timestamp. To avoid errors caused by insufficient synchronization code execution time, I increased the loop time to one minute.

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta  name="viewport" content="width=device-width, > <title>Document</title> </head> <body> <script> const SECUND = 1000; const MIN = SECUND * 60; const HOUR = MIN * 60; function a () { location.href = 'https://www.baidu.com' } a() let time = Date.now() localStorage.start = time // This writing method do not learn, here to save trouble... let targetTime = time + MIN for (; time < targetTime;) { localStorage.end = Date.now() } </script> </body> </html>Copy the code

Finally, when we look at the result, the start timestamp is basically 1s off from the last timestamp

conclusion

Our final conclusion: WebKit redirects tend to be executed asynchronously after a delay of one second. The WebKit-based browser kernel behaves the same way without tweaking the core code we analyzed above.

Then we need to clean up when we use the redirection and page-hopping apis. That is, if you do not want the redirected code to continue to execute, it is recommended to add a sentinel variable to judge the status of the sentinel variable before the subsequent code execution.

At the end of the article, we hope to get your suggestions and improvements, and then we will open another chapter to explain the required jump delay caused by different redirection backgrounds