Javascript的时序和同步机制

嵌入式显示时序控制器(TCON)原理与配置实战:从GLCDC到稳定驱动 在嵌入式图形显示系统中,时序控制器(TCON)是确保图像稳定输出的核心模块,其作用类似于交响乐团的指挥,负责生成精准的同步信号。TCON通过配置行/场同步脉冲的延迟与宽度,将图形处理流水线输出的像素数据流,转换为LCD面板能够正确识别的时序。其核心价值在于适配不同面板的物理特性,如消隐区与同步脉冲参数,从而实现硬件无关的驱动设计。结合系统控制块(SYSCNT)的中断监控功能,可以实时检测数据下溢等异常,保障车载仪表、工业HMI等高可靠性场景的显示稳定性。本文以GLCDC的TCON模块为例,深入解析其信号流、 阅读详情

<译自http://dev.opera.com/articles/view/timing-and-synchronization-in-javascript/>

时序问题是Javascript应用程序中最难解错误的来源之一。在开发中从来不出现的问题可能在终端用户的慢速网络和机器上冒出来。这些问题也可能是间断性的,难以重现。

考虑一个简单的例子:一个按钮,以及与之关联的事件处理函数。当按钮被按下时,其它元素被修改。如果用户在将被修改的元素被解析生成前按下按钮,脚本将会失败。开发人员可能不会注意到这个问题,因为他是在快速的网络和机器环境下测试的,在这种环境下整个页面的解析和生成只在一瞬间就完成了。

本文将尝试解释当前浏览器中各种跟时间有关的Javascript问题。

基本知识

浏览器窗口有一个线程来执行HTML的解析、事件派发以及Javascript代码的执行。Javascript代码以下面两种方式之一执行:

  1. 在<script>标签中的顶级代码在页面载入时执行。
  2. 事件处理函数在事件派发过程中被处理。

由浏览器发起这两种执行,它们都在同一个线程中运行,任何时候都只有一个代码单元在运行。

基本上浏览器由事件驱动(代码通过响应用户输入而运行),但在页面载入期间,还受解析线程的驱动。

事件流

事件是浏览器发出的一个信号,表明窗口正要发生,或者已经发生了某件事。

事件处理程序是一个Javascript函数,注册到一个对象和事件名上。当对应的事件发生在注册的对象上时,事件处理程序即被调用。

所有的事件处理程序都是顺序执行,在任何一个事件完全处理完毕(包括事件沿DOM树冒泡及缺省响应)之前,下一下事件不会被处理。

缺省响应

缺省响应是浏览器事件模型中的最有意思的一环:它发生在没有任何Javascript代码需要执行的时候。比如,一个链接上的点击事件的缺省响应是导航到该URL上。单选框按钮的点击事件的缺省响应是选中该单选框,等等。

缺省响应并不是一个事件处理程序,我们不能移除它或者改写它,这一点是与我们的自定义事件处理程序不同的地方。但是,我们可以在事件派发过程中使用'preventDefault'函数来取消缺省响应的执行(在IE中通过event.returnValue来取消)。即使缺省响应被取消,相关的自定义事件处理器仍然会被激发,只是在此之后,缺省响应不再执行。

派发序列

象load这样的事件只发生在相应的对象上('window'或者'document')。然而,针对文档里特定元素的事件,则在它们祖先级别节点的事件处理程序也会被激发。
当事件在目标节点上被激发之前,存在一个'捕获(cpaturing)'阶段,即位于目标节点的祖先节点上的那些节点可能截获事件。然而事件捕获并不是在所有的浏览器上都能可靠工作。
事件'起泡',即当它们在目标元素上激发之后,会依次在DOM树上的祖先节点上也得到激发,直到遇到document对象,则在所有浏览器上适用。
事件在所有相关元素上被激发以及执行缺省响应,被称作事件派发。
对非冒泡事件,派发顺序是:
  1. 捕获阶段:事件从上至下发生在所有祖先节点上。
  2. 事件在目标元素上激发,即注册在该元素上的事件处理程序被执行(以不确定的顺序)。
  3. 缺省动作被执行(如果没被某个处理器取消掉)。

对冒泡事件,派发顺序是:

  1. 捕获阶段:事件从上至下发生在所有祖先节点上。
  2. 事件在目标元素上激发。
  3. 冒泡阶段:事件在所有祖先元素上被激发,从下而上。
  4. 执行缺省响应(除非被某个事件处理器取消)。

通过调用'stopPropagation()(在IE中是cancelBubble())可以防止事件继续冒泡,但缺省响应仍然会执行。因此取消冒泡和取消缺省响应是分开和独立的操作。

事件模型的每个阶段在DOM 3 Events规范中有详细地解释。

存在着一些奇怪的情况,缺省响应会在事件派发之前产生--但可能依然被取消。举例来说,当一个单选框被点击一,勾选标志被生成,'checked'属性也在事件派发前就已更新。然而,如果缺省动作在事件派发过程中被取消,那么该update会在缺省响应阶段被回滚:勾选标志被移除,'checked'属性被翻转回去。

批量事件

一些事件成批到来:用户的一次输入会导致多个事件被派发。比如,当焦点从一个表单字段移到另一个字段时,前一个字段上发生'blur'(失去焦点)事件,后一个字段上发生'focus'(焦点移入)事件。两个事件在概念上是同时发生(因为它们是对同一个用户输入的响应),但实际上还是顺序派发。

如果是冒泡事件,则只有该事件的捕获/冒泡阶段和缺省响应完全执行以后,下一个事件才会被派发。

该顺序的一个例子是鼠标点击某个按钮并释放的动作。此时'mouseup'事件和'click'事件都被激发,顺序是:

'Mouse-up'事件的派发:

  1. 'click'事件的派发阶段--所有捕获事件处理器都已执行。
  2. 目标元素:事件在目标元素上激发。
  3. 'mouseup'的冒泡阶段:事件在所有祖先级元素上激发。
  4. 缺省响应(本事件无缺省响应)。

'Click'事件的派发

  1. 捕获阶段-所有捕获处理器都已执行。
  2. 目标元素:事件在目标元素上激发。
  3. 冒泡阶段:'click'事件在所有祖先级元素上激发。
  4. 'click'的缺省响应被执行。

在事件派发中只能取消本事件的缺省响应。例如,'mouseup'事件处理程序取消了缺省响应(无意义,因为'mouseup'没有缺省响应)。这并不会阻止'click'事件的激发,因为它们是不同的事件。

然而,缺省响应可能引起其它事件。假如在'submit'按钮上发生一个'click'事件,其缺省动作是提交当前的表单,因此进而产生一个'submit'事件。因此,取消'click'事件上的缺省响应也一并取消了下一个事件。

事件队列

事件的派发是为了响应用户输入(通过鼠标或者键盘),或者象页面载入完成这样的内部事件。然而,输入和派发是两个异步操作。

用户输入可能发生在事件处理器正在执行的时候。这时动作被缓冲起来,当事件派发器再次执行时,这些被缓冲的动作对应的事件被一一派发。事件总是以正确的顺序派发,但在动作和事件派发之间可能会有明显的延迟,如果某些事件处理器代码比较花时间的话。

当事件处理器执行时,IE和Mozilla完全停止对用户的响应,就连工具条也会看上去被锁住一样。尽管用户可能可以进行某些操作,比如点击按钮,但这些动作都只是被缓冲起来,而且不会有任何可见的反馈。这可能看上去让用户困惑,他们极有可能重复点击按钮,从而造成不期望的后果。甚至用户可能认为浏览器已经崩溃,因为它似乎停止响应。

Opera比起来更能响应用户操作,比如如果在脚本还在执行时点击了一个按钮,它能对用户的操作给出可见的反馈。然而,事件仍然被存入缓冲队列,仍然要顺序派发,就象其它浏览器所做的那样。因此缺省响应直到事件处理完毕之前,也不会被执行。同样,这也会使用户困惑,尽管可能不如象IE和Mozilla那样。

基本准则是,事件处理代码不能占用太多时间。特别要当心异步的XMLHttpRequest请求,因为它们可能造成显著的延迟,从而冻住浏览器或者文档窗口。

嵌套事件

有一个特别的场合,事件不是序列化的,而是嵌套的。如果在脚本中通过dispactchEvent(在IE中是fireEvent方法)方法来显式地发出一个事件,该事件会被立即派发。只有当该事件(也包括缺省响应)处理完成后,原来的脚本才会继续运行。

同样,DOM变更事件(这些事件在IE中不支持)也会被立即派发,并与DOM变更同步,比如当appendChild()被调用时。

渲染的时机

编程方式修改的DOM或者样式并不会立即被渲染呈现给用户。这一切取决于浏览器的实现。

例如,如果某元素的背景色被改变,DOM会立即反映这一修改(而且DOM修改事件会被立即派发且同步处理),但我们不能确知何时浏览器引擎会将该变化呈现在屏幕上。似乎Opera会立即将修改渲染出来,而Mozilla和IE则会等该事件处理完毕之后才做渲染。

Timeouts

方法setTimeout将指定的函数计划在指定的时间以后被调度执行:

window.setTimeout(someFunc, 1000);

定时脚本在某种程度上象事件处理器一样工作。尽管它们是响应某个超时,而非用户输入,但象用户事件一样被事件分派线程顺序处理。

因此,你不能指望超时函数在指定的时间被运行。如果其它事件或者批量事件正在执行,超时脚本会被排入队列等待。基本上我们可以确保该函数会在1秒中以后执行,但可能要等待的时间会长于1秒。

令入惊讶地由此产生了一个有用的功能。如果一个处理程序注册为超时0秒后执行,处理程序不会被立即执行,而是被立即存入队列。它会在当前事件(包含缺省响应)执行完毕后立即执行。如果超时事件在一批事件的处理程序中间被创建(比如blur/focus,mouseup/click),超时事件会在该批事件完全完成后被调度。

<译注:在“长时间运行的脚本”一节,作者演示了为什么这个功能实际上相当重要。>

非用户事件

其它非用户发起的事件有:

  • 页面加载事件
  • 超时事件
  • 异步XMLHttpRequest操作数据接收完成时的回调

这些事件象用户发起的其它事件一样被放入事件分发队列。这意味着,XMLHttpRequest响应处理程序不会在数据接收完成时立刻调用,而是被排在事件分发队列中等待执行。

Alerts

警告对话框(以及相关联的confirm/prompt对话框)有一些奇怪的特性。

当脚本发起对话框后,脚本被挂起,只到对话框关闭。从这个意义上讲它们是同步执行的。脚本等待alert()函数返回后才能继续运行。

微妙的是有一些浏览器在alert对话框出现并等待用户操作时仍然允许事件分发。这意味着当脚本被挂起,等待alert()函数返回时,其它事件分发处理中的还可能有函数运行。

用户接口事件,比如mouseup和click不会在alert对话框存在期间被激发,因为alert对话框是模态对话框且捕获所有用户输入。但非用户发起的事件,比如页面加载,超时事件和异步XMLHttpRequest事件仍然有可能被激活。

页面载入

浏览器下载文档时的同时也渐进式地解析和渲染页面。

大多数外部资源,如图片,插件媒体,是被异步地载入的。当解析器遇到img,embed,iframe和object标签时,会产生一个新的线程。这个线程会在主页面解析线程之外独立地下载、解析和渲染该外部资源。在iframes中的页面也是异步加载的。

外部样式表是一个例外。一些浏览器象对待图片一样异步地下载它们,一些浏览器同步下载它们,以避免样式表载入时全部重新渲染整个文档。(这也防止了早期已显示的内容在更换样式表时闪烁)。换句话说,不要依赖这些特殊的行为。

Javascript块的执行

脚本元素被同步解析。当一个脚本元素指向外部链接时,页面的解析工作暂停,直到该外部脚本完全下载并解析运行之后才恢复。

内联脚本块在结束标签遇到时完成解析并执行。

脚本块的执行

Javascript脚本分两阶段处理。先是解析,然后是执行。在解析阶段,验证代码是否符合语言规范,如果有语法错误,脚本不会被执行。

在执行阶段,所有顶级语句会被执行。顶级语句是指除开函数内部代码以外的所有语句。顶级语句可能含有对同一块代码中函数的前向引用,由于函数的声明已经在代码解析阶段被处理过了,所以下面的代码可以工作:

<script>
  var x = getMagicNumber();
  function getMagicNumber() { return 117; }
</script>

然而,下面的代码不会工作,因为函数表达式的求值是在运行时完成的:

<script>
  var x = getMagicNumber(); // ERROR! getMagicNumber is undefined!
  var getMagicNumber = function() { return 117; }
</script>

下面的代码也不能正常工作,因为代码段都是在遇到结束标签时立即执行的:

<script>
  alert(getMessage());
</script>
<script>
  function getMessage() { return "Hello!"; }
</script>

使用document.write()

脚本可能使用document.write()直接产生HTML输出。该输出首先被缓存,直到该段脚本结束执行时才被解析。输出中可能又包含脚本段,它们会在解析的过程中被执行。

生成的HTML输出紧跟在当前脚本段的后面。

DOM构建

解析器在页面加载时增量式地构建DOM树。每遇到一个新标签,一个空的元素就被插入到DOM树中。当开始标签解析完成后,一个非空标签就被插入到DOM中<译注:原文:An empty element is inserted in the DOM when the tag is parsed. A non-empty element is inserted when the opening tag is parsed.可能是指元素的属性值指定在开始标签中,因此当该标签解析完成时,元素就不为空。>例如,当解析器开始解析文档内容时,body元素就在DOM中存在且可用了。

注意DOM不一定完全对应输入的HTML内容。例如HTML和head标签,即便它们不出现在HTML中,这些元素也会被构建在DOM中。

如果HTML源代码无效,比如,title元素出现在body元素中,浏览器会重调DOM,使之有效。因此不能认为DOM树的构建是按序构建的。

延迟的代码段加载

脚本的同步加载有一个缺点:如果文档头里有太多代码要下载和执行,那么页面的渲染可能就会有显著地延迟。

为了减轻这个副作用,我们可以使用script元素的defer属性值。该属性指示浏览器可以异步加载脚本。然而,我们不能肯定当脚本执行时,它是在页面加载完成以前还是以后。Opera浏览器则完全忽略该属性。

<script defer> 
   alert("this message will appear at some unpredictable time during page load"); 
</script>

延迟脚本不能使用document.write(),因为它们不与解析器同步。

脚本块总是按他们在文档中出现的顺序来执行,无论它们是否有着defer属性。因此,如果没有defer属性的脚本元素在有defer属性的元素后面,解析器必须先完成延迟脚本的加载和执行,然后才能进行非延迟脚本的解析和运行。这就消除了defer属性的意义,因此必须将非延迟脚本始终放在延迟脚本的前面。

由于这些原因,defer属性在决定代码段运行时机上并不可靠,它仅仅允许部分浏览器在处理一个代码段的同时继续解析文档。

渐进式渲染

页面的视觉呈现的渲染并非与DOM构建同步。这个时机基本无法预言。取决于网络速度和页面大小,浏览器可能等到整体页面完全下载完毕后再渲染,也可能一次渲染一小部分。

当页面开始渲染时,用户接口就开始响应用户输入事件。如果事件处理程序引用了还未生成的DOM元素,这就可能导致前向引用问题。

可能出错的代码示例:

<button 
onclick="document.getElementById('lamp').backgroundColor = 'yellow'">
  Click here to turn on lamp!
</button>
<div id='lamp'>O</div>

问题可能发生在当用户点击按钮时,lamp元素还没有生成。事件处理程序应该避免引用在其后定义的元素。

在更为复杂的用户接口中,想要在页面控制间避免前向引用可能是不切实际的。相反,所有控制应该一开始处于禁用状态,直到'onload'事件处理程序来激活它们。此时可以确保所有页面元素都已加载。

注意'onload'事件需要等待所有的图片(以及桢等)完成加载。如果页面上有一些大的图片,这可能需要占用一时间。一个变通方法是在页面底部嵌入一个内联脚本,来激活整个页面。这将在页面完成加载时得到执行,但不依赖外部资源的加载。

长时间运行的脚本

理想地,Javascript代码不应该长时间运行,因为它们会中断用户体验。然而有时候可能无法避免这些长时间运行的脚本。在这种情况下,应该给用户显示一个“请等待”的消息或者进度条,来指示浏览器并没有死掉。问题是这条消息必须在可能长时间运行的处理开始之前就要显示。

下面是一段示例伪代码:

headlineElement.innerHTML = "Please wait...";
performLongRunningCalculation();
headlineElement.innerHTML = "Finished!";

在IE和Mozilla中,“请等待”的消息并不会向用户显示,因为该消息只在脚本结束时,浏览器才会将其渲染到飞屏幕上。在Opera中,“请等待”消息则会在计算正在进行时显示。

如果我们想要消息也能正常地在IE和Mozilla中显示,我们必须将立即控制交还给UI,以便消息可以在计算开始前被渲染:

headlineElement.innerHTML = "Please wait...";
function doTheWork() {
   performLongRunningCalculation();
   headlineElement.innerHTML = "Finished!";
}
setTimeout(doTheWork, 0);

现在setTimout的技巧保证了消息在浏览器被阻塞前就能显示出来。当然浏览器仍然可能在计算进行时被“冻”住,因此这个技巧并不是十分优雅。如果我们想要完全防止浏览器被“冻”住,则需要将计算进程分解成一些小的函数,并使用setTimeout将它们链接在一起。不过这样立即就增加了代码的复杂度。

竞争条件

每个窗口(以及桢)都有自己的消息队列。

在Opera中,每个窗口都有自己的Javascript线程。在iframes中的窗口也是这样。结果是在不同桢中激活的消息处理程序可能同时执行。如果这些同时执行的代码共享了数据(比如顶层窗口的属性),我们就有可能遇到竞争条件。

我不在此赘述竞争条件的危害,只想指出这可能导致非常令人困惑的错误。

解决方案之一是,让消息处理函数始终在顶层窗口的消息处理队列中排队,即使它们是被其它桢激发的事件。

假设一个页面含有一个iframe。这个iframe有一个页面'onload'处理函数,将在页面中执行。

// bad onload function in frame:
window.top.notifyFrameLoaded()

这样做是危险的,因为'onload'事件可能在包含页面执行其它脚本时执行。该消息可以被放入队列:

// good onload function in frame
window.parent.setTimeout(window.top.notifyFrameLoaded, 0)

这段代码中重要的部分是使用setTimeout将消息处理排入父窗口消息队列中。

关于时间的建议

  • 不要写长时间运行的脚本
  • 不要使用同步的XMLHttpRequest
  • 不要使在不同桢中激活代码访问全局状态。
  • 不要使用alert对话框来调试,因为这有可能完全改变程序的逻辑。
Codex MCP协议栈深度排错指南:Ubuntu 20.04下AI Agent本地化部署实战 MCP(Model Control Protocol)是现代AI Agent架构中的核心通信协议,其本质是一套标准化的模型控制与工具协同规范,而非简单命令行封装。它通过JSON-RPC 3.0定义能力发现、工具调用与事件响应机制,支撑Skills(可插拔AI外设)与Hooks(操作系统级事件反射)的松耦合协作。技术价值在于实现LLM与专业工具链(如Playwright、Wireshark)的安全、低延迟、资源可控集成,适用于自动化测试、逆向分析、UI智能截图等工程场景。本文聚焦Ubuntu 20.04真实环 阅读详情

相关推荐

别再死记硬背IIC时序图了!用Arduino UNO和逻辑分析仪,5分钟带你亲手抓取并看懂波形

本文通过Arduino UNO和逻辑分析仪实战演示IIC通信协议的波形捕获与解析,帮助读者直观理解起始条件、应答位等关键时序概念。文章详细介绍了硬件连接、软件配置及常见问题排查技巧,让抽象的IIC时序图变得清晰可见,适合嵌入式开发者和电子爱好者学习参考。

weixin_30617695的博客 441

js执行时序 宏任务和微任务

宏任务一般是:包括整体代码script,setTimeout,setInterval、I/O、UI render。 微任务主要是:Promise、Object.observe、MutationObserver process.nextTick nextTick 优先级比 Promise 等 microTask 高,setTimeout和setInterval优先级比setImmediate高。 console.log('script start'); setTimeout(fun...

zhengzhengwang的专栏 407

GBA.js与Wasm模拟器对比:Web复古游戏实现路径深度解析

WebAssembly(Wasm)和JavaScript是当前Web高性能计算的两大核心技术。Wasm作为一种低层级的二进制指令格式,提供了接近原生的执行速度,尤其适合移植C/C++等语言编写的成熟应用;而JavaScript作为Web的通用脚本语言,凭借其即时编译(JIT)优化和广泛的API支持,在开发灵活性和启动速度上具有优势。在复古游戏模拟领域,这两种技术路线的选择直接决定了项目的架构与性能表现。纯JavaScript方案(如GBA.js)通过动态重编译(Dynarec)和Canvas API的极限优

weixin_33701294的博客 379

js程序运行时序原理

js程序运行时序原理1.概念浏览器中每一个Tab代表一个进程,其中每个进程中由多个线程组成,主要由Js引擎线程、HTTP请求线程、定时触发线程、事件触发线程、GUI线程;JS引擎线程:主线程,运行优先级最高,大部分的js语句都在此线程中运行;HTTP请求线程:如axios中请求定时触发线程:如setOutTime中执行的线程事件触发线程:如普通的点击事件,文本改变...

行云的博客 276

Cypress拦截时序问题解析:解决请求先于拦截注册的四种实战策略

在网络请求拦截测试中,时序问题是一个常见挑战,尤其在单页应用(SPA)的端到端测试场景下。其核心原理在于测试框架的命令队列与浏览器事件循环的异步交互机制:如果应用初始化请求在拦截规则注入网络层之前触发,就会导致拦截失效。理解这一机制的技术价值在于,它能帮助开发者编写出更稳定、可靠的自动化测试套件,避免在持续集成(CI)环境中出现偶发性失败。针对Cypress测试中典型的“幽灵请求”问题——即请求先于`cy.intercept()`注册发出——本文提供了从防御到根治的层级化解决方案,包括利用`beforeEa

weixin_30673611的博客 397

GitHub 1.2 万星 Qt 项目 VNote 源码解读(六):加载和渲染 Markdown 文本时的同步机制

VNote 在加载和编辑 Markdown 文档时,通过两个同步机制确保操作顺序:1) 使用 m_ready 标志和待执行队列 m_pendingActions 控制 HTML 模板加载期间的 C++ 操作,待 Js 环境初始化完成后执行积压操作;2) 使用计数器 numOfOngoingWorkers 控制 Markdown 文本渲染期间的前端 Js 操作,采用"最后写入优先"策略处理并发请求。这两个机制分别解决了 Js 环境初始化依赖和 DOM 元素渲染依赖的问题,通过时序控制保证了

Laurence的技术博客 724

JS资源时序问题思考

最近碰到一个问题,涉及JS的时序,借总结梳理梳理思路,事件的处理如下: 资源初始化 加载网络资源:从网络fetch资源,完成后会触发Promise 独立事件-修改资源 其中,修改资源时,资源已初始化,但网络资源加载未完成,导致了异常。

春夜喜雨的专栏 633

指纹浏览器环境的导入、导出、快照与云端同步机制

现代指纹浏览器早已不再是单机版的“参数修改器”,而是演变成了一个**有状态的分布式身份管理系统**。环境不再是临时的进程,而是如同虚拟机般的持久化资产。 本文将深度拆解指纹浏览器环境的导入、导出、快照与云端同步机制,从 Chromium 底层存储拓扑到分布式一致性架构,讲述如何让数字身份在云端获得永生。

数据知道的博客 493

计算机网络时序和同步一样么,异步和同步电路的区别 同步时序设计规则

异步电路1. 电路的核心逻辑是组合电路,比如异步的FIFO/RAM读写信号、地址译码信号等电路;2. 电路的输出不依赖于某一个时钟,也就说不是由时钟信号驱动触发器产生的;3. 异步电路非常容易产生毛刺,且易受环境的影响,不利于器件的移植;同步电路1. 电路的核心逻辑是由各种各样的触发器实现的,所以比较容易使用寄存器的异步复位/置位端,以使整个电路有一个确定的初始状态;2. 整个电路是由时钟沿驱动的...

weixin_42151729的博客 1040

Morris.Js 漂亮的时序线型图

Morris.Js的工作效率也很高,它实际上是一个控制图形的类库。这个使用起来较为简单的API可以绘画出线形图、条形图、面形图和炸面圈图。用完之后你就会发现它的确很方便。

【影像组学入门百问】1#---#3

理论上讲三大主流平台Windows, Linux和MacOS均可进行影像组学研究。根据笔者实际经验,如果内存不足可能导致软件罢工,其余显示、GPU等均非必要。显示:最小分辨率为1024×768(推荐为1280×1024或更好)。Slicer中的许多计算都是多线程的,并且将受益于多核,多CPU配置。计算机需要足够的内存和图形功能将原始数据和处理结果保存在其内存中。如涉及深度学习等方法的研究需根据实际需求配置电脑,无法一概而论。接口设备:推荐使用带滚轮的三键鼠标。内存:超过4GB(推荐8G以上)。

weixin_38594676的博客 1484

JS跨端状态管理实战精要(90%开发者忽略的关键细节)

掌握JS跨端状态管理核心技巧,解决多端数据同步难题。涵盖React Native、小程序等场景,详解状态共享、持久化与性能优化策略。90%开发者忽略的关键细节全解析,值得收藏。

VarIsle的博客 335

PX4飞控与MAVROS实战:从零搭建无人机ROS通信环境(附常见报错解决)

本文详细介绍了如何从零搭建PX4飞控与ROS的通信环境,重点解析了MAVROS的安装、硬件连接、串口权限配置以及坐标系转换等核心步骤。针对GeographicLib数据下载失败、串口权限不足等常见报错提供了实用解决方案,并附有Offboard模式控制的代码示例,帮助开发者快速建立稳定的无人机ROS开发环境。

dapp9builder的博客 335

Readest 段落模式修复实录:从 Shift+P 双重触发到章节回退的调试经验(4717 / PR 4725)

本文以 Readest(开源多端电子书阅读器)段落模式(Paragraph Mode)的一轮真实 bug 修复为线索,完整复盘 PR #4725 如何一次性解决 #4717 上报的三个问题:`Shift+P` 一次按键触发两次切换、overlay 键盘事件被全局监听器吞掉、进入/退出段落模式后阅读位置回退到章节开头。文中不仅给出可复用的修复模式(事件分发器快照迭代、dialog 焦点模式、`vie

gitblog_00831的博客 327

Linux磁盘扩容实战:用parted命令无损扩展/data分区(附常见报错解决方案)

本文详细介绍了在Linux生产环境中使用parted命令对已挂载的/data分区进行在线磁盘扩容的完整实战流程。通过风险评估、状态检查、parted工具深度解析及实战演练,指导用户安全完成动态扩容,并提供了常见报错如'Partition is being used'、MBR 2TB限制等的解决方案,确保业务不中断、数据不丢失。

weixin_29207439的博客 297

第二十届全国大学生智能汽车竞赛极速光电组:MicroPython与恩智浦RT1021的硬件编程实战指南

本文为参加第二十届全国大学生智能汽车竞赛极速光电组的同学提供了一份详尽的MicroPython与恩智浦RT1021硬件编程实战指南。文章深入剖析了选择MicroPython与RT1021这对组合的优势,详细讲解了从开发环境搭建、基础硬件控制(如GPIO、PWM、编码器、CCD)到系统集成(平衡控制、循迹算法)与多任务调试的全过程,旨在帮助参赛者降低嵌入式开发门槛,高效备赛。

wdx0123456的博客 844

Mermaid Live Editor:专业图表实时编辑的深度解析与实践指南

Mermaid Live Editor是Mermaid.js官方推出的在线图表编辑器,为技术文档编写者、产品经理和开发人员提供了**实时编辑与预览**的图表创作体验。这个基于浏览器的工具完全免费开源,支持流程图、时序图、甘特图等8种专业图表类型,所有操作都在本地完成,确保数据隐私安全。 ## 🧩 架构设计与技术实现 ### 现代前端技术栈构建 Mermaid Live Editor采用**

gitblog_00364的博客 859

Python爬虫实战:中国土地市场网招拍挂数据抓取与分析

本文详细介绍了如何使用Python爬虫技术从中国土地市场网抓取土地招拍挂数据,并进行初步的数据分析与可视化。文章涵盖了爬虫的基本原理、反爬虫策略应对、数据清洗与存储、数据分析与可视化等多个方面,为土地市场研究者提供了一套完整的数据获取与分析解决方案。

2201_76125261的博客 684

终极图表神器:如何在Draw.io中轻松使用Mermaid插件

你是否厌倦了在图表制作工具和代码编辑器之间来回切换?想要用简单的文本描述快速生成专业图表,同时又保留可视化编辑的灵活性吗?Draw.io Mermaid插件正是你需要的完美解决方案!这个强大的开源插件将Mermaid的文本驱动优势与Draw.io的可视化编辑能力完美结合,让你既能用代码快速生成标准化图表,又能享受拖拽调整的便捷性。 ## 为什么你需要这个Draw.io Mermaid插件? 在

gitblog_00596的博客 253

6、Cocos2D游戏开发:精灵添加与角色实现

本文详细介绍了在Cocos2D游戏开发中如何添加背景精灵和玩家角色精灵。通过创建GameScene场景、组织项目资源、使用多分辨率图像适配不同设备,并深入讲解了将角色拆分为上下半身以实现更真实瞄准效果的原理。文章还解析了Cocos2D的图像搜索机制、锚点概念及其应用,以及如何通过父子节点关系管理复合角色。最终实现了猎人角色在场景中的正确显示与定位,为后续动画和交互功能打下基础。

e3f4g5的博客 90

利用R批量计算相关系数

批量求相关系数

weixin_52073820的博客 1458

Draw.io Mermaid插件:代码驱动与可视化编辑的融合解决方案

在现代软件开发和技术文档编写过程中,图表是不可或缺的沟通工具。然而,传统图表制作面临两大挑战:代码生成图表缺乏可视化编辑的灵活性,而可视化工具又难以实现版本控制和自动化。Draw.io Mermaid插件通过将Mermaid的文本驱动优势与Draw.io的可视化编辑能力完美结合,为技术团队提供了革命性的图表工作流解决方案。 ## 问题背景:传统图表制作的效率瓶颈 在技术文档、系统设计和项目管理

gitblog_00684的博客 219

【MATLAB代码】雷达观测目标跟踪模型|H-infinity Filter(H无穷大滤波)与EKF(扩展卡尔曼滤波)的对比。附完整代码,订阅专栏后可直接查看

对比了经典扩展卡尔曼滤波(EKF)与H∞优化的EKF(H∞-EKF)在目标跟踪中的性能。通过MATLAB仿真实验,结果显示:在存在模型误差和测量噪声的情况下,H∞-EKF相比经典EKF在位置误差上降低

985工科博士毕业,专攻定位、导航和滤波等算法研究。从业10年,主要使用MATLAB 243

5分钟上手Strapi时序数据管理:从定时采集到智能分析全攻略

Strapi作为领先的开源无头CMS,凭借100% JavaScript/TypeScript构建的特性,为开发者提供了灵活高效的时序数据管理解决方案。本文将带你快速掌握如何利用Strapi的定时任务功能实现数据自动采集,并通过内置工具完成智能分析,让你在5分钟内搭建起完整的数据处理流程。 ## 为什么选择Strapi进行时序数据管理? Strapi的无头架构使其成为时序数据管理的理想选择。它

gitblog_00297的博客 1062

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

多线程环境 竞态条件 和 防护策略 详解(附:JavaScript 中进程和线程的总结)

竞态条件是指多线程环境下多个线程同时访问和操作共享数据时,由于执行顺序不确定导致结果异常的现象。本文详细解析了竞态条件的定义、核心概念、典型示例(如银行转账问题)以及常见类型(检查后行动模式、数据竞争等)特别探讨了JavaScript和Node.js环境中的竞态条件表现形式,分析了其根本原因(非原子操作、共享状态等),并提供了检测方法(代码审查、压力测试)。最后总结了多种解决方案,包括互斥锁、原子操作、不可变数据等,以及前端场景下的特殊处理方式(请求取消、序列化处理),为开发者提供了全面的竞态条件防护策略。

木木的学习笔记 917

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

深入解析GTM TIO双比较指令:复杂时序控制与PWM生成实战

在嵌入式系统开发中,定时器是控制时序、生成PWM波形的核心硬件模块。其工作原理基于比较匹配机制,通过设定计数值与比较值,在特定时间点触发事件或改变输出电平,从而实现精确的时间控制。这项技术的核心价值在于为电机驱动、电源管理和通信协议等应用场景提供了高精度、高可靠性的时间基准。GTM(通用定时器模块)作为现代高性能微控制器中的高级定时器外设,其TIO子模块的双比较指令功能,通过主从通道协同与多种工作模式,极大地扩展了传统单通道比较的能力,能够高效实现非对称PWM、精确死区控制以及基于多事件触发的复杂状态机,是

cuk0051的博客 540

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

下一篇: Javascript:变量,静态变量和this
yaaron
博客等级 码龄19年 7粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值