In the process of developing a small program recently, I met a requirement that the header should be accompanied with accessToken when requesting. AccessToken is a parameter returned through the login interface, and it may be expired, so I need to log in again. Therefore, the locally stored accessToken verification will be performed every time the applets are loaded. However, under the operation mechanism of applets, the onLaunch of APP and the onLoad of Pages will be executed concurrently. In the case of weak network, concurrency may lead to incomplete accessToken verification. The page request function starts executing. It is easy to cause an interface exception. The original solution would be to await the checkAccessToken method in app.js before each page calls the interface, but this is not very friendly to write
Solution:
An additional layer of lock is encapsulated on the basis of request. Before accessToekn check is completed, all other incoming requests are waited. Other requests are not requested until the check is completed
The principle of analysis
- Encapsulate the original request
- Make use of the feature of Promise and the feature of JS object stored in memory, together with async/await, make other requests wait for the key request to complete before starting the request, so as to realize the request lock
- First wait for the critical request to complete, and then go back to determine whether it is needed
The code analysis
First, simulate a request
Const mockRequest = (name, time = Math.random() * 1000) => new Promise(reslove => { console.log(`${name}---------------run`); setTimeout(() => { reslove(`${name}---------------done`); }, time); });Copy the code
Define request lock
The request lock manages two states, one is the critical request is in progress state, the other is when the critical request fails, need to wait for the auxiliary operation to complete state
const lock = { wait: null, runing: null };
Copy the code
Add a layer of encapsulation on top of request
- Parameter Settings: withOutLock is used to skip logic for certain requests that do not need to wait, and lockOthers is used to lock requests that come in after critical requests
- Critical requests come in and are executed directly,
lock.runing
Pending status is assigned to a key request directly. When other requests come in, the request is not initiated, and the other requests are executed only after the main request is completed
Const request = async (name, opts = {withOutLock: false, lockOthers: false, hasErr: If (opts.withoutLock) {const res = await mockRequest(' ${name} - withOutLock '); if (opts.withoutLock) {const res = await mockRequest(' ${name} - withOutLock '); console.log(res); return; } / / key request completes Other request has reached the awaited state if (lock. Running) {the console. The log (` ${name} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- wating... `); await lock.runing; } if (opts.lockothers) {lock.runing = mockRequest(name, 4000); let res = await lock.runing; // Empty to lock. Runing = null; If (opts.haserr) {lock. Wait = mockRequest(" key request exception handling ", 4000); } else { console.log(res); return; If (lock.wait) {console.log(' Waiting for critical request exception processing... `); await lock.wait; // Empty wait lock lock.wait = null; Console. log(' Critical request exception handling completed '); } const res = await mockRequest(name); console.log(res); return; };Copy the code
Simulated operation effect
Const mockConcurrent = () => {for (let I = 0; i < 5; I++ {setTimeout () () = > {request (` concurrent requests ${I} `, {withOutLock: I = = = 0}). }, Math.random() * 100); }}; Request (" Critical requests - others must wait to complete ", {lockOthers: true, hasErr: false}); mockConcurrent();Copy the code
Runtime effect
The last
After my colleague’s advice, I plan to explore the request pool and implement the request context in the future
Demo code: Specific example code demo reference
Pure technical exploration, pit point unknown, welcome to point out mistakes and deficiencies