请求方客户端代码的封装方式,请教一下大家
发布于 3 年前 作者 helloMane 2468 次浏览 来自 问答

们目前项目中的代码专门针对程序的边界做了一层封装,尤其是调用第三方应用的请求相关的代码。但是我感觉不是特别的好,且看下面这一段伪代码

  • 类的定义
const axios = require('axios');

class Client {
  constructor({ url, username, password }) {
    this.url = url;
	this.username = username;
	this.password = password;
	this.token = '';
	
	this.login = this.login.bind(this);
	this.getSomething = this.getSomething.bind(this);
	
	this.login();
  }
  
  async login() {
    const { token } = await axios.post(...);
	this.token = token;
  }
  
  async getSomething(params) {
    if (!this.token) {
	  console.error('未登录');
	  return;
	}
	
    const result = await axios.get(..., {
	  headers: {
	    token: this.token,
	  },
	  ...
	});
	
	return result;
  }
}
  • 调用
const Client = require('./Client.js');

async main() {
  const client = new Client({
    url: '127.0.0.1',
	username: 'zhangsan',
	password: '...'
  });
  
  const result = await client.getSomething();
  
  console.log(result);
}

他这里在实例化该对象是,构造函数调用了一个async的函数,如果立即调用getSomething()方法,可能会存在login()方法还未执行完,token还没有的情况。 请问一下大家一般是怎样封装这样的类的?或者说怎样处理这样的情况?

4 回复

这个类似Node.js里调socket.connect返回一个socket,然后立刻调write一样,这时候可能还没有建立连接,处理就是getsomething的时候判断是否在获取token,不是的话直接请求,不然就把请求放到队列里或者基于事件订阅也行,token获取成功后,执行等待队列的请求或者触发事件。

讲设计应该先从调用代码开始

调用代码的意图看起来是想对外隐藏login这一层逻辑, 以减少调用方的复杂度

目前的实现, 一定运气上解决了这个问题, 运气是看什么时候调用 getSomething()

修正办法: 存储login 返回的promise, 让 getSomething() 检查这个 promise

class Client{
  constructor(){
	 this.pmsLogin = this.login()
  }
  
  async getSomething(){
	await this.pmsLogin
	if(!this.token) {
	  // 此处应有重试, 超时策略等
	}
  }
}

@theanarkh 目前我能想到的方案也和你的一致,不过总感觉这样的客户端封装不如直接函数式编程了,反而有点增加工作量的味道了

@netwjx 感谢,看来终究还是绕不开这个操作呀=.=

回到顶部