1.generator 执行机制分析
2.ES6及ESNEXT
3.使用 Next.js + Ethers.js 开发加密钱包
4.next.js 源码解析 - API 路由篇
5.nodejs原理&源码赏析(7)Node.js中的源码事件循环,定时器和process.nextTick
6.AI驱动的分析前端UI组件生成器(Next.js,GPT4,源码Langchain和CopilotKit)
generator 执行机制分析
本文以下面代码为例,分析分析 generator 执行机制相关的源码源码,版本为 V8 7.7.1。分析软文街源码
首先,源码当 let iterator = test() 开始执行时,分析V8 调用 Runtime_CreateJSGeneratorObject,源码创建一个生成器对象。分析此函数逻辑是源码创建 JSGeneratorObject 的实例,设置相关属性后返回生成器对象 generator。分析此时生成器对象 generator 被保存在累加器中。源码在字节码 SuspendGenerator 的分析处理函数中,该函数暂停当前函数的源码执行,并多次调用 StoreObjectField 来保存生成器函数当前运行的状态。最后返回累加器中的值,即生成器对象 generator。因此,生成器函数在执行到“第一次暂停”的位置时,处于暂停状态。
在有了生成器对象后,可以调用其 next 方法让生成器函数继续执行。当 JavaScript 代码继续执行 iterator.next() 时,生成器对象的 next 方法被调用。生成器函数恢复执行需要 CPU 的寄存器操作。在笔者的成语填字小游戏源码 Mac 下,调用链路为GeneratorBuiltinsAssembler::GeneratorPrototypeResume-> CodeFactory::ResumeGenerator-> Builtins::Generate_ResumeGeneratorTrampoline。之后,调用 X 汇编,使生成器函数在暂停处恢复执行。此过程通过 Builtins::Generate_ResumeGeneratorTrampoline 函数完成,函数通过将未来要返回的地址压栈,并跳转到生成器函数 test 暂停的地方,继续执行。
生成器函数从暂停处继续执行后,字节码一行一行往下执行,直到遇到下一个 SuspendGenerator,即“第二次暂停”。这是由 yield 带来的。yield 被 V8 编译成 SuspendGenerator 和 ResumeGenerator 两条字节码,分别表示保存状态暂停和恢复状态继续执行。
async/await 与 generator 的关系分析:async/await 和 generator 都有暂停当前函数执行并从暂停处恢复执行的能力。await 和 yield 对应的字节码都是 SuspendGenerator 和 ResumeGenerator。生成器函数暂停时,需要调用生成器对象的 next 方法来从暂停处恢复执行。async 函数依赖 Promise 和 microtask,当 V8 在执行 microtask 队列时,已经暂停的 async 函数恢复执行。async 函数通过 Generator 和 Promise 获得保存状态暂停和恢复状态执行的能力,以及自我驱动向下继续执行的能力,从而避免调用 next 方法。
JavaScript 中的在线制制图网站源码函数类型较为复杂。虽然在 JavaScript 中,1 和 0.1 都是 number,但在 V8 中它们是不同的类型,内存表示和 CPU 运算指令也有所不同。因此,即使在 JavaScript 中 typeof 都返回 function 的 test、test1、test2,在 V8 中是不同的类型。日常开发中,当一个组件/方法需要一个函数做为参数时,需要确保正确传递 ES6 之前的函数、async 函数或生成器函数,以避免运行时错误。
原生 generator 与 babel 转译的区别:在日常开发中,生成器/async 函数会被 babel 转译成类似下面的代码。这段代码中,test 函数被多次调用,但由于闭包保存了函数执行的状态,每次调用 test 都是新的 test。这种实现非常巧妙,但与 V8 中生成器函数的原理有较大区别。Babel 转译的代码无法生成字节码 SuspendGenerator 和 ResumeGenerator。
总结:生成器函数被调用时,开始执行并返回生成器对象后暂停。调用 iterator.next() 后,新爱玩暗宝源码生成器函数从第一次暂停的位置恢复执行,遇到 yield(SuspendGenerator)后第二次暂停。
ES6及ESNEXT
一.let与const
块级作用域,const定义之后不可改变,变量提升。
二.箭头函数
箭头函数的特点:this是在定义时决定的,普通函数this是在调用时决定的。箭头函数不能用在构造函数,构造函数里this会指向新创建出来的对象,箭头函数里this指向是在定义时决定的。
三.类
四.模版字符串
五.解构
5.1 数组的解构
5.2 对象的解构
5.3 解构的原理:针对可迭代对象的Iterator接口,通过遍历器获取对应的值进行赋值
5.4 Iterator接口,为各种不一样的数据解构提供统一的访问机制。任何数据解构只要有Iterator接口,就能通过遍历操作,依次按顺序处理数据结构内的所有成员。es6 for of相当于遍历器,在遍历数据结构时,自动寻找该接口
六. 遍历
6.1 for in缺点:会遍历原型链上的可枚举属性;适合遍历对象,不适合遍历数组
6.2 for of可迭代对象(Array、Set、String、TypedArray,arguments对象,NodeList对象)上创建迭代循环,调用自定义迭代钩子。优点:仅遍历当前对象;可中断
七. Object
7.1 Object.keys返回一个给定对象的斗棋联盟源码购买自身可枚举属性组成的数组
7.2 Object.values返回一个给定对象可枚举属性值的数组
7.3 Object.entries返回一个给定对象自身可枚举属性的键值对数组
7.4 Object.getOwnPropertyNames返回自身拥有的枚举或不可枚举属性名称字符串数组
7.5 Object.getOwnPropertyDescriptor属性描述符,是一个对象,包含以下内容: configurable: 若为false,则任何删除目标属性或修改属性特性(writable, configurable,enumerable)的行为将被视为无效,故一般设置为true; writable: 若为false,则修改该属性的操作都无效(不会报错,严格模式下会报错),默认false; enumerable: 是否能够在for-in或者Object.keys遍历出来
7.6 Object.create()创建一个新的对象,将第一个参数作为新对象都protp属性的值。
7.7 Object.assign浅拷贝,类似于{ ...a, ...b}
八. 数组
8.1 Array.flat()按照指定深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为新数组返回
8.2 Array.includes判断数组是否含有指定值,含有返回true,否则返回false;含有两个参数
8.3 Array.find返回数组中满足提供的测试函数的第一个元素值,否则返回undefined.
8.4 Array.from创建一个新数组实例,数组的元素由可迭代对象的值组成
8.5 Array.of创建一个具有可变数量参数的数组新实例,而不考虑参数的数量或类型
九. 异步编程: async await yield
十. Babel
是一个工具链,将ES+版本的代码转换为向后兼容的js语法,以便能运行在当前和旧版本的浏览器中。抽象语法树(AST)处理过程中每一步都涉及到创建或操作抽象语法树。每一层都有相同的结构,这样的每一层结构被叫做节点,一个AST树有单一或多个节点构成,组合在一起可以描述用于静态分析的程序语法。Babel的处理步骤:解析parse, 转换transform, 生成generate。接收代码并输出AST,接收AST并对其遍历,对节点进行添加、更新及移除操作。这是最复杂的过程,需要插件介入,把最终的AST转化成字符串形式的代码,同时会创建源码映射(source maps)。
补充知识点: Proxy将Object对象的某些明显属于语言内部的方法放到Reflect对象上。Reflect对象的方法与Proxy对象的方法一一对应,Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
使用 Next.js + Ethers.js 开发加密钱包
本文详尽介绍了如何使用 Next.js 和 Ethers.js 开发一个加密钱包,是 Web3 前端开发者的理想入门教程。Ethers.js 是在 Web3 交互中常用的 SDK,尤其在与智能合约打交道时,它能简化繁琐的原生 JS 工作。Ethers.js 入门与优势
Ethers.js 作为与智能合约交互的首选库,相较于早期的 web3.js,更受欢迎。它支持节点即服务模式,无需本地部署高昂成本,像 Alchemy、Infura 和 Tenderly等服务提供了便捷的连接。使用 Alchemy 作为服务提供商
我们以Alchemy为例,首先在dashboard.alchemy.com创建应用,选择 Ethereum 和 Goerli 网络,获取 API key。在接下来的开发中,Key 会被用于连接服务。构造合约和读取信息
要与合约互动,首先需要构造一个合约对象,包括地址、abi 和 provider。ethers.js 提供多种Provider选项,如JsonRpcProvider。连接 MetaMask 钱包
MetaMask 是最常见的数字钱包,通过浏览器插件与Ethers.js配合,调用ethereum.request方法获取用户已登录的账户信息,进行安全的交易操作。创建钱包和转账交易
转账前需创建 Wallet 实例,可以随机生成或使用助记词和私钥。转账时,创建交易对象并调用wallet.sendTransaction,异步等待交易确认。通过合约转账
在合约实例中,使用transfer方法执行转账,同样异步等待交易完成。使用 Next.js 开发钱包应用
用 Next.js 开发的加密钱包项目包含连接钱包、显示信息和转账功能。通过Context简化状态管理,并将组件化设计应用到Wallet、Connect、Details和Transfer组件中。源码与体验
完整代码可参考GitHub链接,或在线体验地址webnext.cloud。对Web3感兴趣的同学,欢迎加入Web3交流群,与Noah探讨更多内容,添加微信:LZQ。next.js 源码解析 - API 路由篇
本文深入解析 next.js 的 API 路由实现细节,以清晰的步骤指引,帮助开发者更好地理解此框架如何管理与处理 API 请求。首先,我们确认了源码的位置位于 next.js 的 packages 文件夹中,重点关注与 API 路由相关的组件。
在排查 CLI 源码的过程中,我们注意到启动 API 路由的命令,如 `start` 和 `dev`,其实际操作逻辑位于 `next/dist/bin/next` 文件中。通过分析这一文件,我们得知这些命令最终调用的是 `lib/commands.ts` 文件中的 `start` 和 `dev` 函数。
深入 `lib/commands.ts` 文件,我们发现 `start` 和 `dev` 函数通过 `lib/start-server` 中的 `startServer` 方法实现。在 `startServer` 方法中,`ponents`的文件夹,并在其中包含`Header.tsx`与`CodeTutorial.tsx`两个文件。`Header.tsx`负责定义导航栏,`CodeTutorial.tsx`则展示生成的UI组件、嵌入式代码编辑器及实现教程。在`page.tsx`文件中,导入并定义`Home`函数组件,用于整合`Header`和`CodeTutorial`组件。在完成上述步骤后,删除`globals.css`中的CSS代码,并添加自定义CSS以优化界面外观。运行`npm run dev`命令,然后访问`http://localhost:/`,以预览UI组件生成器的前端界面。
接下来,我们将利用CopilotKit将AI功能集成到组件生成器中。CopilotKit提供了前端与后端包,允许您通过React状态与AI代理进行互动。首先,在`CodeTutorial.tsx`中导入`useMakeCopilotReadable`和`useCopilotAction`自定义钩子。在`CodeTutorial`内部,使用这些钩子设置上下文与生成代码及教程的动作。这将允许通过应用内聊天机器人进行交互,以生成UI组件代码和实现教程。
在`page.tsx`文件中,导入CopilotKit前端包,并将`CopilotSidebar`与`CodeTutorial`组件集成,以实现在前端展示生成的代码与教程。通过配置CopilotKit后端端点与聊天机器人,您能够利用AI代理处理请求,生成代码并提供教程。此外,集成Tavily AI代理,以进行在线主题研究。
配置完后端服务,通过在终端中运行命令并访问`http://localhost:`,您将能体验到AI驱动的UI组件生成器功能。通过应用内聊天机器人提示生成特定组件,如“生成一个联系表单”,生成的代码与教程将立即呈现于界面上,您可直接在嵌入式代码编辑器中进行调整。
至此,您已成功构建了一个AI驱动的前端UI组件生成器。CopilotKit的集成使得AI功能变得触手可及,极大地提升了开发效率。这一构建过程不仅展示了AI在软件开发领域的强大应用,也为未来的项目集成提供了灵感与参考。通过GitHub链接,您可以访问完整的源代码,深入了解实现细节。在AI技术的驱动下,未来的开发流程将更加智能化与高效。