当前位置: 首页 > wzjs >正文

大兴企业网站建设公司时彩网站开发

大兴企业网站建设公司,时彩网站开发,广州市专业做网站,开发公司成本管理​ 原创作者:庄晓立(LIIGO) 原创时间:2025年03月10日(发布时间) 原创链接:https://blog.csdn.net/liigo/article/details/146159327 版权所有,转载请注明出处。 20250310 LIIGO备注&…


原创作者:庄晓立(LIIGO)
原创时间:2025年03月10日(发布时间)
原创链接:https://blog.csdn.net/liigo/article/details/146159327
版权所有,转载请注明出处。

tauri-splash


20250310 LIIGO备注:本文源自系列文章第1篇《初次体验Tauri和Sycamore (1)》,从中抽取出来独立成文(但并无更新和修订),专注于探究Tauri通道的底层实现(实际上也没有足够底层)。理由:1.原文已经很长,需要精简;2.原文主体是初级技术内容,仅这一节相对深入,显得格格不入。(如无意外,这将是本系列文章的终结。)


20241118 LIIGO补记:出于好奇,简单研究一下Tauri通道的底层实现。

在JS层,创建Channel对象生成通道ID,并关联onmessage处理函数;在传输层,通过invoke()调用后端Command,传入Channel对象作为参数(实质上是传入通道ID);在Rust层,根据通道ID构造后端Channel对象,向客户端指定的Channel发送Message。如何向通道发送Message是后续关注的重点。


JS层创建Channel的源码如下:

class Channel<T = unknown> {id: number// @ts-expect-error field used by the IPC serializerprivate readonly __TAURI_CHANNEL_MARKER__ = true#onmessage: (response: T) => void = () => {// no-op}#nextMessageId = 0#pendingMessages: Record<string, T> = {}constructor() {this.id = transformCallback(({ message, id }: { message: T; id: number }) => {// the id is used as a mechanism to preserve message orderif (id === this.#nextMessageId) {this.#nextMessageId = id + 1this.#onmessage(message) // 前端用户收到此message// process pending messages// ...} else {this.#pendingMessages[id.toString()] = message}});}// ...
}function transformCallback<T = unknown>(callback?: (response: T) => void, once = false): number {return window.__TAURI_INTERNALS__.transformCallback(callback, once)
}

JS层Channel构造函数内部,调用transformCallback为一个回调函数生成唯一ID(它基于Crypto.getRandomValues()的实现能保证ID唯一吗我存疑),并将二者关联至window对象:window['_回调ID'] = ({message, id})=>{ /*...*/};。此处生成的ID也称为通道ID,将被invoke函数传递给Rust层(参见上文前端调用Command)。后端数据通过通道到达前端后,可通过通道ID反查并调用该回调函数接收后端数据。注意区分通道ID、消息ID和后文的数据ID。


Rust层通过JavaScriptChannelId::channel_onChannel::new_with_id构造Channel对象实例。

impl JavaScriptChannelId {/// Gets a [`Channel`] for this channel ID on the given [`Webview`].pub fn channel_on<R: Runtime, TSend>(&self, webview: Webview<R>) -> Channel<TSend> {let callback_id = self.0;let counter = AtomicUsize::new(0);Channel::new_with_id(callback_id.0, move |body| {let i = counter.fetch_add(1, Ordering::Relaxed);if let Some(interceptor) = &webview.manager.channel_interceptor {if interceptor(&webview, callback_id, i, &body) {return Ok(());}}let data_id = CHANNEL_DATA_COUNTER.fetch_add(1, Ordering::Relaxed);webview.state::<ChannelDataIpcQueue>().0.lock().unwrap().insert(data_id, body);webview.eval(&format!("window.__TAURI_INTERNALS__.invoke('{FETCH_CHANNEL_DATA_COMMAND}', null, {{ headers: {{ '{CHANNEL_ID_HEADER_NAME}': '{data_id}' }} }}).then((response) => window['_' + {}]({{ message: response, id: {i} }})).catch(console.error)",callback_id.0))?;Ok(())})}
}

Channel::new_with_id有两个参数,一个是通道ID(或称callback_id),一个是向前端发送数据的on_message函数。这个on_message的命名有误导性,让人以为是接收函数,但看Channel::send()函数源码可以确认on_message是发送函数。

impl<TSend> Channel<TSend> {fn new_with_id<F: Fn(InvokeResponseBody) -> crate::Result<()> + Send + Sync + 'static>(id: u32,on_message: F,) -> Self {// ...}/// Sends the given data through the channel.pub fn send(&self, data: TSend) -> crate::Result<()> where TSend: IpcResponse, {(self.on_message)(data.body()?)}
}

Rust层Channel发送数据的实现代码就在上面JavaScriptChannelId::channel_on(webview)函数内部,即new_with_id()的on_message参数闭包函数内,它主要干了如下几件事:

  • 生成数据ID(data_id):let data_id = CHANNEL_DATA_COUNTER.fetch_add(1, Ordering::Relaxed);
  • 将要数据存入发送缓存队列并关联data_id:webview.state::<ChannelDataIpcQueue>()...insert(data_id, body)
  • 生成JS代码并提交给前端执行(分两步):webview.eval(JSCODE)
    • fetch: invoke('plugin:__TAURI_CHANNEL__|fetch', null, ...data_id...)
    • callback: window['_通道ID']({ message: response, id: {i} }) (调用JS端回调函数, {i}为此通道内消息ID,即序号)

再看一下fetch源码(上文invoke('plugin:__TAURI_CHANNEL__|fetch', ...)将调用此后端Command):

#[command(root = "crate")]
fn fetch(request: Request<'_>,cache: State<'_, ChannelDataIpcQueue>,
) -> Result<Response, &'static str> {if let Some(id) = request.headers().get(CHANNEL_ID_HEADER_NAME).and_then(|v| v.to_str().ok()).and_then(|id| id.parse().ok()){if let Some(data) = cache.0.lock().unwrap().remove(&id) {Ok(Response::new(data))} else {Err("data not found")}} else {Err("missing channel id header")}
}

fetch命令的作用是从发送缓存队列中取出与参数data_id关联的数据返回给前端,同时从发送缓存队列中移除。fetch执行后,通过通道发送的数据就从后端到了前端。注意时序,是后端主动提交JS代码让前端执行,前端才被动发起fetch调用,Tauri正是通过这种方式实现后端向前端“推送”数据。数据被推送至前端后,可能还要经历缓存阶段才提交给Channel用户,确保用户有序接收。


调用链:(JS层)创建Channel,发起调用后端某Command(传入通道ID),(Rust层)把通道ID反序列化为Channel,将待发送数据缓存,调度前端执行JS代码(webview.eval()),(JS层)通过fetchCommand拉取后端缓存数据,处理乱序数据接收,执行用户层onmessage回调,完成单次数据传输。

我原来猜测通道Channel是Command之外另一种更高效的数据传输方案,但事实证明我错了。通过上述源码分析可知,Channel实际上是基于Command实现的更高层的逻辑抽象。Tauri通道发送数据,本质上还是调用Command,只是经过封装之后更适合“后端推送流式数据”应用场景。相比使用普通无通道Command传输数据,其区别在于工作模式:无通道传输,是前端单次主动拉取;有通道传输,是后端多次主动推送,且保证有序送达。


文章转载自:

http://x1D4iIrW.jrpmf.cn
http://qKjGW2rJ.jrpmf.cn
http://MFBLQVa3.jrpmf.cn
http://2QVghou4.jrpmf.cn
http://Mpy56COU.jrpmf.cn
http://ijD36zDi.jrpmf.cn
http://W4XM1j90.jrpmf.cn
http://mE6CrS5W.jrpmf.cn
http://X1ZMuEN8.jrpmf.cn
http://SBuH8PCE.jrpmf.cn
http://19eLimQh.jrpmf.cn
http://uMh8GCzH.jrpmf.cn
http://WqECqUyq.jrpmf.cn
http://pI1xm1Ez.jrpmf.cn
http://9BIu5Sva.jrpmf.cn
http://sPEWuLye.jrpmf.cn
http://KABwa2CX.jrpmf.cn
http://DHdJbpex.jrpmf.cn
http://j8svwgzz.jrpmf.cn
http://LgPzIIye.jrpmf.cn
http://7oLqcSjg.jrpmf.cn
http://yqf3Nnma.jrpmf.cn
http://tGWI2J83.jrpmf.cn
http://MZ8F1EqU.jrpmf.cn
http://kGAix3Ro.jrpmf.cn
http://X1VhF89p.jrpmf.cn
http://IV4FDRjT.jrpmf.cn
http://fb1MoBHl.jrpmf.cn
http://w9WtOJBF.jrpmf.cn
http://wNmL2mSG.jrpmf.cn
http://www.dtcms.com/wzjs/706454.html

相关文章:

  • 网站制作公司运作方案wordpress 手机lianxu播放
  • 成都营销型网站建设公司亦庄网站设计
  • dw建设网站如何加入音乐网站建设与管理指什么
  • 计算机网络技术 网站建设方向网站开发行业知识新闻
  • 宜城营销型网站套餐网站的建设与运营模式
  • 做网站的相关协议绵阳专门做网站的公司
  • 叮当设计网站动易网站无法安装
  • 福州网站开发培训赣州seo培训
  • 山西省消防总队建设工程备案网站惠州模板网站建设
  • 湖南郴州市汝城县win10系统优化软件哪个好
  • 保定网站seo企业做网站的公司
  • 男的女的做那个视频网站wordpress 的模板
  • 2015做哪个网站能致富滕州网站建设助企网络
  • 网站开发与维护介绍好的买手表网站
  • 网站架构分析教育海报设计素材网站
  • 网站页面设计的重要性乐东黎族自治县住房建设局网站
  • wordpress获取文章内容过滤空格四川大学网站seo诊断报告
  • 营销策划方案案例范文廊坊视频优化展现
  • 西安网站建设技术外包设计制作网站收费
  • 成立网站建设领导小组的通知工业设计的网站
  • wordpress主题建站网页设计师工资一般多少钱一个月
  • 深圳服务网站设计哪家公司好大连市营商环境建设监督局网站
  • 郴州网站建设哪里比较好网站建站网站多少钱
  • 福建住房和建设网站密码忘记python做网站验证码
  • 眉山网站开发孝感市网站建设公司
  • 简单个人网站欣赏想找工作去哪个网站
  • 网页设计作业成品免费百度云seo网站建设教程
  • 网站建设几点关门扬中零壹网站建设
  • 帝国建设网站韩漫网站建设
  • 阜阳微网站建设多少钱上传网站