最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

全新 JavaScript 框架 Qwik:以独特的可恢复性方式提速网页应用

  • 2022-11-22
    北京
  • 本文字数:3414 字

    阅读完需:约 11 分钟

全新JavaScript框架Qwik:以独特的可恢复性方式提速网页应用

AngularJS 的创造者Misko Hevery近期宣布了新网络框架Qwik测试版本的推出,声称无论应用程序有多大,Qwik 都能够快速地构建。在多数情况下,Qwik 会先下载 1KB 的 JavaScript,在需要的时候才会懒加载或预处理程序和应用程序代码。


在一次名为《如何从主线程中移除99%的JavaScript》的演讲中,Hevery 介绍了 Qwik 背后的原理。


Qwik 的目标很简单,确保复杂的网站也能在谷歌页面速度评分项上拿到 100/100……归根究底,就是要让互动时间尽可能地缩短。

 

如你所见,行业中的大多数框架都能在优化图片和 CSS 上做到尽善尽美,但 JavaScript 方面却又乏善可陈。因为这对于互联网上的每个人来说都是系统性的问题,我的意思是说,问题根源在于工具而不是开发者。

 

用于优化 JavaScript 交付速度的工具是 Qwik 关注的问题。


Misko 将 JavaScript 在互动时间指标上负面的表现归因于水合(Hydration)作用。水合在连接服务器的渲染时出现。服务器接收到客户端对页面的请求后,做出对应查询以填充界面,并将结果返回客户端。虽然对用户来说,服务器端的页面渲染速度通常要比客户端渲染的页面要快(如更快的首次内容绘制),但页面却并不是立即就可交互的,客户端还需要下载并执行页面上的 JavaScript 脚本。

 

在多数框架中,这种首次交付的 HTML 与应用程序的 JavaScript 协调的过程称作水合。在水过程中,Web 应用程序框架将事件处理程序和 DOM 元素相连接,并初始化应用程序状态。水合之后用户操作会被事件处理程序捕捉,从而使页面可交互。

 

Qwik 保留了服务器端的渲染,通过在服务器上运行应用程序以避免水合。它将所有相关状态信息序列化,将页面内容和序列化的状态一起以 HTML 的形式发送给客户端。这些相关的状态信息包括时间监听器、内部数据结构,以及应用状态。借助序列化的状态,客户端可以接力完成服务器端没有执行完的任务

 

处理交互性的 JavaScript 加载默认是延迟进行的,一般是直到用户实际使用交互时才启动,也就是说一个按钮的事件处理程序最晚可以在用户点击按钮时加载。这种即时的 JavaScript 获取加上预取策略,利用浏览器的本地能力,在不影响页面交互性的前提下完成了文件的加载。

 

在 Qwik 文档中有详细的介绍:

 

Qwik 只会预取当前页面需要的代码,避免下载与静态组件相关的代码。最坏的情况是 Qwik 预取的代码量与现有框架的最佳情况相同,而在大多数情况下,Qwik 所预取的代码只会比现有框架要少。

 

除主线程之外的其他线程都可以做到代码预取,大多数浏览器甚至支持主线程之外的代码 AST 语法预分析。


如果用户在预取完成之前开始交互,浏览器会自动优先交互模块于其他预取模块。

 

Qwik 可以将应用程序分解成部分,这些分块可以按照用户交互的概率高低顺序进行下载。

 

Qwik 网站为开发者提供了教程、实例,以及学习和尝试 Qwik 的在线运行平台。以简单的计数器为例,由一个按钮和显示按钮点击次数的文本框组成,实现方法如下:


import { component$, useStore } from '@builder.io/qwik';
export const App = component$(() => { const store = useStore({ count: 0 });
return ( <div> <p>Count: {store.count}</p> <p> <button onClick$={() => store.count++}>Click</button> </p> </div> );});
复制代码


开发者可以通过 Qwik 的component$ API 创建可恢复组件,有状态的组件可以通过useStore API 显示其对某段状态的依赖。在处理程序的名字后附加$ 字符创建可恢复的事件处理程序(如前文例子中的onclick$ )。通过这些手动添加的提示,Qwik 可以将应用程序文件打包,以实现并优化 JavaScript 的懒加载。前文的计数器程序在服务器端渲染的 HTML 如下:


<!DOCTYPE html><html  q:container="paused"  q:version="0.11.1"  q:render="ssr"  q:base="/repl/21kry8ac4hl/build/">  <html>    <head q:head>      <title q:head>Tutorial</title>    </head>    <body>      <!--qv q:id=0 q:key=AkbU84a8zes:-->      <div>        <p>          Count:          <!--t=1-->0<!---->        </p>        <p>          <button            on:click="app_component_div_p_button_onclick_8dwua0cjar4.js#App_component_div_p_button_onClick_8dWUa0cJAr4[0]"            q:id="2"          >            Click          </button>        </p>      </div>      <!--/qv-->    </body>  </html>  <script type="qwik/json">    {"ctx":{"#2":{"r":"0!"}},"objs":[{"count":"1"},0],"subs":[["2 #0 0 #1 data count"]]}  </script>  <script id="qwikloader">    ((e,t)=>{const n="__q_context__",o=window,r=new Set,i=t=>e.querySelectorAll(t),s=(e,t,n=t.type)=>{i("[on"+e+"\\:"+n+"]").forEach((o=>l(o,e,t,n)))},a=(e,t)=>new CustomEvent(e,{detail:t}),c=(t,n)=>(t=t.closest("[q\\:container]"),new URL(n,new URL(t.getAttribute("q:base"),e.baseURI))),l=async(t,o,r,i=r.type)=>{const s="on"+o+":"+i;t.hasAttribute("preventdefault:"+i)&&r.preventDefault();const a=t._qc_,l=null==a?void 0:a.li.filter((e=>e[0]===s));if(l&&l.length>0){for(const e of l)await e[1].getFn([t,r],(()=>t.isConnected))(r,t);return}const d=t.getAttribute(s);if(d)for(const o of d.split("\n")){const i=c(t,o),s=b(i),a=performance.now(),l=u(await import(i.href.split("#")[0]),s),d=e[n];if(t.isConnected)try{e[n]=[t,r,i],f("qsymbol",{symbol:s,element:t,reqTime:a}),await l(r,t)}finally{e[n]=d}}},f=(t,n)=>{e.dispatchEvent(a(t,n))},u=(e,t)=>{if(t in e)return e[t];for(const n of Object.values(e))if("object"==typeof n&&n&&t in n)return n[t]},b=e=>e.hash.replace(/^#?([^?[|]*).*$/,"$1")||"default",d=e=>e.replace(/([A-Z])/g,(e=>"-"+e.toLowerCase())),p=async e=>{let t=d(e.type),n=e.target;for(s("-document",e,t);n&&n.getAttribute;)await l(n,"",e,t),n=e.bubbles&&!0!==e.cancelBubble?n.parentElement:null},v=e=>{s("-window",e,d(e.type))},w=()=>{var n;const s=e.readyState;if(!t&&("interactive"==s||"complete"==s)&&(t=1,f("qinit"),(null!=(n=o.requestIdleCallback)?n:o.setTimeout).bind(o)((()=>f("qidle"))),r.has("qvisible"))){const e=i("[on\\:qvisible]"),t=new IntersectionObserver((e=>{for(const n of e)n.isIntersecting&&(t.unobserve(n.target),l(n.target,"",a("qvisible",n)))}));e.forEach((e=>t.observe(e)))}},q=(e,t,n,o=!1)=>e.addEventListener(t,n,{capture:o}),y=t=>{for(const n of t)r.has(n)||(q(e,n,p,!0),q(o,n,v),r.add(n))};if(!e.qR){const t=o.qwikevents;Array.isArray(t)&&y(t),o.qwikevents={push:(...e)=>y(e)},q(e,"readystatechange",w),w()}})(document);  </script>  <script>    window.qwikevents.push("click")  </script></html>
复制代码


注意,HTML 文件是通过以下方式强化的。


  • q: 属性,如q:baseq:idq:key

  • 包含特定框架信息的 HTML 注释,如<!--qv q:id=0 q:key=AkbU84a8zes:-->

  • 序列化状态,如<script type="qwik/json"> {"ctx": ..., "objs":[{"count":"1"},0], "subs":[["2 #0 0 #1 data count"]]} </script>

  • 用于在客户端恢复应用程序执行的 Qwik 脚本,如<script id="qwikloader"> ... </script>window.qwikevents.push("click")


Qwik 的在线代码运行平台可以让开发者了解到程序代码是如何被切割打包的,还是用前面的计数器为例,客户端的打包方式如下:



如截图所示,计数器的应用程序被分成了三个脚本。当用户点击按钮时,动态下载并执行其中两个脚本(Qwik 运行时间和 click 事件处理程序的代码)。



参考Qwik文档了解具体执行情况以及代码拆分的原理。Qwik 的网站给出了大量包括教程示例,以及演示在内的信息,还有一个可互动的在线代码运行平台。Qwik 社区中同样也有一个非常简单的电子商务示例,一般对电子商务的厂商来说,页面加载速度提高收入也会增加。


Qwik 团队目前由 AngularJS 的创造者 Miško Hevery、基于 Go 语言 Web 架构 Gin 的创造者 Manu Almeida、Web组件编译器Stencil的创造者 Adam Bradley 组成。

 

目前,Qwik 已推出测试版,且采用 MIT 许可开源,欢迎各位在遵循 Qwik行为准则的前提下贡献代码。


原文链接:

New Qwik JavaScript Framework Seeks Faster Web Apps with Unique Approach: Resumability

2022-11-22 11:488767

评论

发布
暂无评论
发现更多内容

A Comprehensive Guide IPQ5018-IPQ6010-IPQ6018-IPQ8072-IPQ8074

wallyslilly

IPQ6010 ipq6018 IPQ8072

真香!NineData SQL 开发全面适配 GaiaDB

NineData

数据库 百度云 数据源 NineData GaiaDB

低代码平台源代码交付的重要性

互联网工科生

源码 软件开发 低代码

CyberData镜像增量构建实践

数新网络官方账号

镜像增量 增量构建

2024年,你应该知道的Linux新命令

伤感汤姆布利柏

漫谈数据分布可视化分析

百度Geek说

数据分析

2024年API经济的十大预测

幂简集成

API API经济

分享6个当下最受欢迎的 Vue UI 库

伤感汤姆布利柏

Garden Planner for Mac(园林绿化设计软件) v3.8.58注册激活版

iMac小白

探秘SuperCLUE-Safety:为中文大模型打造的多轮对抗安全新框架

不在线第一只蜗牛

人工智能 大模型 ChatGPT

华为云软件开发生产线CodeArts前端DevOps实践

华为云PaaS服务小智

云计算 软件开发 华为云

JavaScript 的新数组分组方法

EquatorCoco

JavaScript 数组 开发语言

【前沿技术】 阿里开源搜索引擎Havenask的消息系统

阿里技术

搜索引擎 消息系统 Havenas 阿里开源

AI技术革命下的平台能力升级:大模型时代的挑战与机遇

百度开发者中心

人工智能 大数据 计算 大模型

不懂技术也能轻松搭建网站!美国虚拟主机的简易指南!

一只扑棱蛾子

虚拟主机 美国虚拟主机

专精特新“广东造” | 华大北斗:从“芯”出发 挺起产业“脊梁”

江湖老铁

graphpad prism for Mac(专业医学绘图工具) v10.2.0激活版

iMac小白

OpenAI Sora 关键技术详解:揭秘时空碎片 (Spacetime Patches) 技术

Baihai IDP

程序员 AI openai 白海科技 sora

小程序SDK在金融、医疗和教育等场景中的安全性保障

Geek_2305a8

什么是DevOps

华为云PaaS服务小智

DevOps 软件开发

Aiseesoft AnyCoord for Mac(GPS虚拟定位软件) v1.0.36激活版

iMac小白

网络技术探析:SDN、SD-WAN、CDN和SDH的关联与演进

Ogcloud

SD-WAN 企业网络 SD-WAN组网 SD-WAN服务商 SDWAN

语言大模型的现状与未来趋势

百度开发者中心

深度学习 大模型 人工智能、

听 GPT 讲 client-go 源代码 (11)

fliter

听 GPT 讲 client-go 源代码 (12)

fliter

低代码开发:拖拉拽自定义表单的创新之道

这我可不懂

软件开发 低代码

SD-WAN如何降低运维成本、简化运维工作?

Ogcloud

SD-WAN 企业网络 SD-WAN组网 SD-WAN服务商 SDWAN

Native Instruments Kontakt 7 for Mac v7.8.1激活版下载

iMac小白

Metasequoia 4 for Mac(水杉3D建模器) v4.8.6e激活版

iMac小白

跨越千年医学对话:用AI技术解锁中医古籍知识,构建能够精准问答的智能语言模型,成就专业级古籍解读助手(LLAMA)

汀丶人工智能

人工智能 自然语言处理 LLM 医疗大模型

SD-WAN保障tiktok海外直播网络的稳定性

Ogcloud

SD-WAN 企业网络 SD-WAN组网 SD-WAN服务商 SDWAN

全新JavaScript框架Qwik:以独特的可恢复性方式提速网页应用_语言 & 开发_Bruno Couriol_InfoQ精选文章