# 7、请求等待机制

一般需要登录的小程序,运行后第一个请求的接口是登录,而其余接口需要等待登录接口完成后才能执行。

如果这个小程序只有一个页面/或者固定首页入口,我们可以将登录接口直接写到首页代码里,通过 js 代码 await 等方式,实现登录接口的前置。

await login();
1

但审批不同,审批有多个页面,且部分场景可以直接访问子页面(如发给用户的审批消息卡片),登录接口逻辑就需要写到根入口(如:App.vue)下.

// App.vue
<script>
	export default {
		onLaunch: function (option) {
			console.log('App Launch', option)
			// 登录
			loginAndGetToken()
		},
		onShow: function () {
			console.log('App onShow')
		},
		onHide: function () {
			console.log('App onHide')
		}
	}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可这么一来,第一个页面的请求,就无法很好的判断登录接口是否完成,因为第一个访问页面 与 App.vue 的渲染是很快的,请求很可能在登录接口回来之前,就发出去了。

所以,我们需要一个请求等待机制,目的:其他接口需要在登录接口执行完之后再执行,机制:是在登录接口逻辑执行时,阻塞其他接口执行,登录接口执行完毕,该阻塞释放。

定义一个阻塞类

// blockRequest.js
/**
 * 用于阻塞接口请求,某个接口请求处理完毕后才能请求其他接口的情况(比如登录
 */
class BlockRequest {
    constructor() {
        this._events = []
        this.isBlocked = false
    }
    // 获取当前状态是否阻塞
    getStatus() {
        return this.isBlocked;
    }
    // 将状态至于阻塞
    blockRequest() {
        this.isBlocked = true
    }
    // 阻塞释放,并将已订阅的时间执行
    freeRequest() {
        this.isBlocked = false
        this._events.forEach((func) => {
            func && func()
        })
        this._events = []
    }
    // 订阅事件
    pushEventlistener(listener) {
        this._events.push(listener)
    }
}

const blockRequest = new BlockRequest();

export default blockRequest;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

在登录接口逻辑处前后,分别加上 “请求阻塞” 和 “阻塞释放”

// login.js
import blockRequest from './blockRequest';

await function loginAndGetToken() {
  blockRequest.blockRequest(); // 请求阻塞
  await login();
  // ...todo (设置好token之类的)
  blockRequest.freeRequest();  // 阻塞释放
}

1
2
3
4
5
6
7
8
9
10

request 请求前置方式配置如:

// request.js
import blockRequest from './blockRequest';

// 等待请求释放方法
const pendFree = async () => {
  return new Promise((resolve) => { 
    // 订阅阻塞释放事件
    blockRequest.pushEventlistener(() => resolve({}))
  })
}

// 网络请求配置
const service = (url, method = 'GET', params = {}, header = {}) => {
  return new Promise(async (resolve) => {
    // 当前接口释放需要阻塞等待(ignoreBlock 是**白名单机制,登录接口需要在白名单中,否则登录接口也被阻塞**
    if (!header.ignoreBlock && blockRequest.getStatus()) { 
      await pendFree(); // **阻塞释放后,才往下继续执行**
    }
    // todo ... 封装token等参数逻辑
  
    bz.request({
      ...
    })

  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

从上面方法可以看出,我们只需在登录接口逻辑处和请求封装处添加上阻塞逻辑即可,页面上的请求逻辑不要添加额外逻辑,该怎么写就怎么写。

如此,在登录接口执行的时候,页面上的接口虽然会正常执行,但会一直处于前台 pending 状态,待登录接口执行后,才会发出。

最后更新于 : 7/20/2023, 9:03:05 PM