上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

nodejs源码 ConnectWrap的Dispatch调用分析

[复制链接]
  • TA的每日心情
    擦汗
    昨天 09:20
  • 签到天数: 192 天

    [LV.7]常住居民III

    687

    主题

    5428

    回帖

    6365

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    6365

    荣誉开发者管理员油中2周年生态建设者喜迎中秋

    发表于 2023-2-9 00:36:00 | 显示全部楼层 | 阅读模式

    我们可以看一段代码

      ConnectWrap* req_wrap =  new ConnectWrap(env,  req_wrap_obj, ...);  
      req_wrap->Dispatch(uv_tcp_connect,  
                         &wrap->handle_,  
                         reinterpret_cast<const sockaddr*>(&addr),  
                         AfterConnect);  

    这里调用了Dispatch是属于ReqWrap类的

    template <typename T>
    template <typename LibuvFunction, typename... Args>
    int ReqWrap<T>::Dispatch(LibuvFunction fn, Args... args) {
      Dispatched();
      CallLibuvFunction<T, LibuvFunction>::Call(
          fn,
          env()->event_loop(),
          req(),
          MakeLibuvRequestCallback<T, Args>::For(this, args)...);
    }

    Dispatched是一个设置data,不用管,可以看到这里调用了 CallLibuvFunction<T, LibuvFunction>::Call
    我们去看看看Call的代码

    // Detect `int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);`.
    template <typename ReqT, typename... Args>
    struct CallLibuvFunction<ReqT, int(*)(uv_loop_t*, ReqT*, Args...)> {
      using T = int(*)(uv_loop_t*, ReqT*, Args...);
      template <typename... PassedArgs>
      static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
        return fn(loop, req, args...);
      }
    };
    
    // Detect `int uv_foo(uv_req_t* request, ...);`.
    template <typename ReqT, typename... Args>
    struct CallLibuvFunction<ReqT, int(*)(ReqT*, Args...)> {
      using T = int(*)(ReqT*, Args...);
      template <typename... PassedArgs>
      static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
        return fn(req, args...);
      }
    };
    
    // Detect `void uv_foo(uv_req_t* request, ...);`.
    template <typename ReqT, typename... Args>
    struct CallLibuvFunction<ReqT, void(*)(ReqT*, Args...)> {
      using T = void(*)(ReqT*, Args...);
      template <typename... PassedArgs>
      static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
        fn(req, args...);
        return 0;
      }
    };

    因为我们调用的uv_tcp_connect的函数表达式是
    int uv_tcp_connect(uv_connect_t req,

    uv_tcp_t
    handle,

    const struct sockaddr* addr,

    uv_connect_cb cb)
    所以应该执行的是

    // Detect `int uv_foo(uv_req_t* request, ...);`.
    template <typename ReqT, typename... Args>
    struct CallLibuvFunction<ReqT, int(*)(ReqT*, Args...)> {
      using T = int(*)(ReqT*, Args...);
      template <typename... PassedArgs>
      static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
        return fn(req, args...);
      }
    };

    所以我们调用的是
    uv_tcp_connect(req(), MakeLibuvRequestCallback<T, Args>::For(this, args)...)
    args收集是

    template <typename LibuvFunction, typename... Args>
    int ReqWrap<T>::Dispatch(LibuvFunction fn, Args... args) 

    也就是Dispatch除了fn的函数那就是

    三个
    我们拼接上得到了

    uv_tcp_connect(req(), MakeLibuvRequestCallback<T, Args>::For(this, &wrap->handle_,  
    reinterpret_cast<const sockaddr*>(&addr),  
    AfterConnect)...)

    现在我们看看MakeLibuvRequestCallback是什么

    template <typename ReqT, typename T>
    struct MakeLibuvRequestCallback {
      static T For(ReqWrap<ReqT>* req_wrap, T v) {
        return v;
      }
    };
    
    template <typename ReqT, typename... Args>
    struct MakeLibuvRequestCallback<ReqT, void(*)(ReqT*, Args...)> {
      using F = void(*)(ReqT* req, Args... args);
      static void Wrapper(ReqT* req, Args... args) {
        ReqWrap<ReqT>* req_wrap = ReqWrap<ReqT>::from_req(req);
        F original_callback = reinterpret_cast<F>(req_wrap->original_callback_);
        original_callback(req, args...);
      }
      static F For(ReqWrap<ReqT>* req_wrap, F v) {
        req_wrap->original_callback_ = reinterpret_cast<typename ReqWrap<ReqT>::callback_t>(v);
        return Wrapper;
      }
    };
    

    可以看到分为两种情况
    如果传入的第二个参数不是函数,则将参数直接原封不动传出去,如果是函数,则进行包裹返回一个函数
    我们这里第二个参数是&wrap->handle_
    一个handle
    所以会透传,那么最后

    uv_tcp_connect(req(), MakeLibuvRequestCallback<T, Args>::For(this, &wrap->handle_,  
    reinterpret_cast<const sockaddr*>(&addr),  
    AfterConnect)...)

    会变成

    uv_tcp_connect(
    req(), 
    &wrap->handle_,  
    reinterpret_cast<const sockaddr*>(&addr),  
    AfterConnect
    )

    刚好符合tcp的调用头

        int uv_tcp_connect(uv_connect_t* req,  
                           uv_tcp_t* handle,  
                           const struct sockaddr* addr,  
                           uv_connect_cb cb) {  
          // ...  
          return uv__tcp_connect(req, handle, addr, addrlen, cb);  
        }  
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.net/a/lihengdao666
    个人宣言:この世界で私に胜てる人とコードはまだ生まれていません。死ぬのが怖くなければ来てください。

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表