美文网首页
JavaScript对象延迟初始化,动态生成 gRPC 调用实例

JavaScript对象延迟初始化,动态生成 gRPC 调用实例

作者: _delong | 来源:发表于2020-10-26 23:37 被阅读0次

需求背景是这样的

在 GraphQL (Apollo Server)服务中对接 gRPC 服务,对接服务中包含多个在不同目录层级的 proto 文件,并且存在互相引用,以及对 google proto文件的引用。同时,在开发过程中 Apollo Server 会使用 Mock 模式,在使用 Mock 模式时不希望初始化 gRPC 客户端实例,因为本地没有 gRPC 服务。

抽象后的要求是

  • 支持 动态引用 proto文件
  • 支持 proto 的 import 语法
  • 支持 proto 的 package 语法
  • 支持指定 proto 的引入目录
  • 支持直到使用时才创建实例的 延迟初始化
const grpc = require("@grpc/grpc-js");
const loader = require("@grpc/proto-loader");
const path = require("path");

function client(filename, package, service) {
    const definition = loader.loadSync(`${filename}`, {
        keepCase: true,
        longs: String,
        enums: String,
        defaults: true,
        oneofs: true,
        // CAUTION: proto files import path relative from 2 places
        includeDirs: [
            path.join(__dirname, "./current/path"),
            path.join(__dirname, "./path/to/proto/root"),
            path.join(__dirname, "./path/to/other/extra"),
        ],
    });
    const proto = grpc.loadPackageDefinition(definition);

    let Client = proto;
    for (let i of [...package.split("."), service]) {
        if (i) Client = Client[i];
    }

    return new Client(
        process.env.GRPC_PEDESTAL_URI,
        grpc.credentials.createInsecure()
    );
}

let _clients = {};

function proxy(file, package, service) {
    if (!file || !package)
        throw Error("Target must contain file and service field");

    function getCachedlient() {
        const K = file + package;
        if (!_clients[K]) _clients[K] = client(file, package, service);
        return _clients[K];
    }

    const handler = {
        get: function (target, prop, receiver) {
            let client = getCachedlient();
            return function () {
                let [params, callback] = arguments;
                if (callback) {
                    client[prop](...arguments);
                } else {
                    return new Promise((resolve, reject) => {
                        client[prop](params, (err, res) => {
                            if (err) reject(err);
                            else resolve(res);
                        });
                    });
                }
            };
        },
    };
    return new Proxy({ file, package, service }, handler);
}

const clients = {
    ClientA: proxy(
        "path/to/a.proto",
        "EntryService"
    ),
    ClientB: proxy(
        "path/to/some_within_a_package.proto",
        "com.company.project.demo.v1",
        "EntryService"
    ),
};

module.exports = clients;

注意事项:

  1. 加载 proto 文件的 includeDirs 要与 proto 文件的保存目录匹配
  2. proto 的 package 需要手动指定,否则无法使用
  3. 延迟加载的机制,即使是在变量被引用后,也不会初始化,直到真正被当做方法使用时才会初始化

参考内容

https://javascript.info/proxy

相关文章

  • JavaScript对象延迟初始化,动态生成 gRPC 调用实例

    需求背景是这样的 在 GraphQL (Apollo Server)服务中对接 gRPC 服务,对接服务中包含多个...

  • JS Class

    JavaScript 语言中,生成实例对象的传统方法是通过构造函数 JavaScript语言中,生成实例对象的传统...

  • JVM06 Java中对象的内存是如何布局的?

    Java中创建对象的方式 new -通过调用构造器来初始化实例字段反射-通过调用构造器来初始化实例字段Object...

  • JS 实例

    JavaScript 实例JavaScript 对象 实例JavaScript Browser 对象 实例Java...

  • java为什么静态方法只能调用静态方法

    因为静态方法是属于类的,动态方法属于实例对象,动态方法只有在对象实例化之后才存在, 如果静态方法能调用动态方法的话...

  • swift中的可失败初始化器+反初始化器

    可失败初始化器 可能返回nil 反初始化器 当类的实例对象被释放内存时,就会调用实例对象的deinit方法

  • Java 基础

    类和对象 对象:对象是类的一个实例,有状态和行为。 创建对象:声明,new 实例化,调用构造方法初始化对象。 类:...

  • servlet(待补充)

    servlet生命周期 1.初始化,调用init()方法,生成Servlet实例2.响应客户请求,调用servic...

  • Vue组件开发实践

    软件编程界有一个面相对象的思想, 或者用另一句话就是为实例写模板, 初始化的时候调用模板(类)生成实例, 进行抽象...

  • math与字符串常用方法

    Math对象 Math是 JavaScript 的原生对象,提供各种数学功能。该对象不是构造函数,不能生成实例,所...

网友评论

      本文标题:JavaScript对象延迟初始化,动态生成 gRPC 调用实例

      本文链接:https://www.haomeiwen.com/subject/ndramktx.html