找到
281
篇与
易航
相关的结果
- 第 2 页
-
JavaScript 循环中的闭包陷阱:“意料之外” 的共享 闭包 (Closure) 无疑是 JavaScript 中最强大、最迷人的特性之一。它赋予了函数访问其定义时所在词法环境的能力,即使该函数在其定义的作用域之外执行。凭借闭包,我们可以实现数据封装、模块化、柯里化等高级编程技巧。 然而,硬币的另一面是,闭包也常常被视为 JavaScript 中最容易误解、最容易出错的特性之一。稍有不慎,就会掉入闭包的“陷阱”,导致内存泄漏、意外的变量共享等问题。 图片 在循环中使用闭包时,很容易出现意外的变量共享问题。 图片 在这个例子中,我们期望 setTimeout 的回调函数(闭包)分别输出 0, 1, 2, 3, 4。但实际输出的却是 5 次 5。这是因为 setTimeout 是异步执行的,当回调函数执行时,循环已经结束,i 的值已经变成了 5。而且,由于使用了 var 声明 i,所有的回调函数共享的是同一个 i 变量。 解决方法: 使用 let 声明循环变量:let 具有块级作用域,每次循环都会创建一个新的 i 变量,避免了变量共享。 图片 使用立即执行函数 (IIFE):创建一个立即执行函数,将循环变量 i 作为参数传递进去,形成一个闭包,每次循环都会创建一个新的作用域。 图片 使用bind方法:使用 bind 方法将循环变量 i 绑定到回调函数上。 图片
-
JavaScript 内存泄漏:“永不消逝” 的变量 闭包最常见的陷阱就是内存泄漏。当一个闭包引用了外部函数的变量,而这个闭包又被长期持有(例如,作为事件处理程序或定时器回调),那么外部函数的变量就无法被垃圾回收,导致内存泄漏。 function createHandler() { let largeObject = new Array(1000000).fill("data"); // 创建一个大对象 return function() { console.log("Handler clicked"); // 没有直接使用 largeObject, 但由于闭包的存在, largeObject 无法被回收 }; } document.getElementById("myButton").addEventListener("click", createHandler());在这个例子中,createHandler 函数返回一个事件处理函数(闭包)。这个闭包引用了 createHandler 函数的 largeObject 变量。即使我们没有在事件处理函数中直接使用 largeObject,但由于闭包的存在,largeObject 无法被垃圾回收,导致内存泄漏。 解决方法: 解除引用:在不需要闭包时,手动解除对闭包的引用,例如: let handler = createHandler(); document.getElementById("myButton").addEventListener("click", handler); // ... 当不再需要事件处理程序时 ... document.getElementById("myButton").removeEventListener("click", handler); handler = null; // 解除对闭包的引用避免不必要的闭包:如果不需要访问外部函数的变量,就不要创建闭包。 将变量设置为null: 在闭包中, 将不再需要的外部变量手动设置为null。 图片
-
书接前文 Markdown 进阶玩法 前几天写了一篇关于 Markdown 的科普文章Markdown 基础语法 ⇲,本文继续探讨 Markdown 相关扩展语法。 图片 内嵌HTML标签 Markdown 语法的标记相较于 HTML 还是小菜一碟,当然作为一种写作格式语言,大部分时候是够用的。如果需要进一步优化文字视觉表现力,可以在 Markdown 中内置一些 HTML 和 CSS 样式来改善。 使用时,只需使用 HTML 本身标签即可,无需在其前面添加前缀或分隔符来表明你正在从 Markdown 切换到 HTML。 行内标签 HTML 的行内标签如<span>、<cite>、<del>不受限制,可以在 Markdown 的段落、列表或是标题里任意使用。如果你喜欢,可以直接采用 HTML 标签来格式化。 Less is <strong>more</strong>.(strong 是 HTML 加粗标签)<strong> 标签渲染效果如下: Less is more . 内嵌 CSS 样式 还可以在 Markdown 中嵌入 CSS 样式,和HTML一起使用。 例如,给段落加 CSS 样式: <p style="color:#009;font-style:italic;"></p>换了颜色及倾斜后渲染效果如下: Life is the art of drawing sufficient conclusions form insufficient premises. 区块标签 使用 HTML 区块标签 <div>、<table>、<pre>、<p> 时,必须在前后加上空行与其它内容区隔开,开始标签和结束标签不能用Tab或空格来缩进。 例如在 Markdown 文件里插入 HTML 表格: <table> <tr> <td>Name</td> <td>Age</td> <td>No.</td> </tr> <tr> <td>Tom</td> <td>21</td> <td>01</td> </tr> </table>标签渲染效果如下: Name Age No. Tom 21 01 要注意的是,在 HTML 区块标签间的 Markdown 格式语法将不会被处理。比如在 HTML 区块内使用 Markdown 样式的 *强调* 会没有效果。 插入视频 Markdown 不具有插入视频的功能,好在我们依然可以利用它支持 HTML 标签的特性,用 <video> 标签来插入视频。 视频插入格式如下: <video width="100%" controls src="https://txmov2.a.kwimgs.com/upic/2025/02/14/20/BMjAyNTAyMTQyMDQzMzZfMTMxMzM1NzkxNF8xNTY5NDg0Mzg5NzVfMl8z_b_B7664d41afc4fb15f0f117a1ffe825663.mp4"></video>显示效果如下: 标题 ID 许多 Markdown 编辑器支持标题的自定义 ID,方便直接链接到标题并使用 CSS 对其修改。 书写格式是在标题后边用大括号包裹自定义的 ID 。 ##### Have a nice day {#my-id}对应 HTML 是这样的: <h5 id="my-id">Have a nice day</h5><h5> 标签渲染效果如下: Have a nice day页内锚点跳转 利用指定标题 ID ,通过链接格式可实现页面内目录跳转,链接锚点会自动滚动到屏幕顶端。 把指定 ID 放在标题后面,注意大括号左边的空格不可少。 ### Test title {#custom} [Jump here](#custom)如果 Markdown 工具不支持上述 {#custome} 语法(比如MarktText),还可以使用 span 标签,为元素添加 id 来实现。 <span id ="custom">Test title</span> [Jump here](#custom)跳转渲染效果如下: Test title Jump here 任务列表 创建带有复选框的 TODO List 任务列表,请在任务列表前面添加破折号-和方括号[ ],注意,破折号和方括号之间,以及方括号里面要加空格。选择哪个复选框,就在方括号[x]里面添加 x 。 - [x] This is the first one - [ ] This is the first two复选框渲染效果如下: [x] This is the first one [ ] This is the first two 定义列表 简单来说,就是对多个术语的定义和描述。要创建定义列表,请在第一行上键入术语。在下一行,输入一个冒号,后跟一个空格和详细定义。 Frist List : This is the List Description Second List : This is another List Description对应 HTML 像这样: <dl> <dt>Frist List</dt> <dd>This is the List Description</dd> <dt>Second List</dt> <dd>This is another List Description</dd> </dl>渲染效果如下: Frist List This is the List Description Second List This is another List Description 围栏代码块 基本 Markdown 语法允许你通过缩进四个空格或一个制表符来创建代码块,如果觉得不方便,可以尝试用围栏代码块。 在代码块前后使用三个反引号`,或三个波浪号~~~。 \```json { "firstName": "John", "lastName": "Smith", "age": 25, } \```如果想让代码高亮显示,在代码块的反引号后面指定一种语言,比如 Java: \```java System.out.println(Hello World); \```渲染效果如下: System.out.println(Hello World);表格 在 Markdown 基础篇里我们介绍了创建表格的方法,这里再扩展一下表格的样式。 单元格宽度可以通过横向连字符--自由控制。 | No. | Age | Time | | --| ------- | -------- | | 18 | 24 | 2025.01.21 |如下所示,渲染效果看起来相同。 No.AgeTime18242025.01.21在连字符---左侧、右侧或两侧添加冒号:,来控制列表文本左、右、中对齐。 | No. | Name | Birthday | | :-- | :-----: | ------------: | | 18 | 24 | 08.18 | 渲染效果如下: No.NameBirthday182408.18Emoji表情 有两种方法可以将表情符号添加到 Markdown 文本中,一是从 emojipedia 网站上复制表情符号并粘贴到文本中,另外一种是直接输入 emoji shortcodes,使其包裹在两个冒号中间。 *刚出去散步* :Walking: *看见了一只猫咪* :cat:表情符号渲染效果如下: 刚出去散步 🚶♂️ 看见了一只猫咪 🐱 反斜杠转义 有时候会希望插入一些符号而不想被当作 Markdown 标记渲染,就需要对这些符号进行转义。方法是,在字符前面添加反斜杠字符\。 例如,我想用星号*加在文字旁边做强调效果,可以这样写: \* Are you OK?渲染效果如下: * Are you OK? 可转义的字符 Markdown 支持以下这些符号前面加上反斜杠,从而达到转义目的。 \ backslash ` backtick * asterisk _ underscore {} curly braces [] square brackets () parentheses # hash mark + plus sign - minus sign (hyphen) . dot ! exclamation mark特殊字符自转义 在 HTML 中,有两个字符需要特殊处理:< 和 &。左尖括号用于开始标记;& 符号用于表示 HTML 实体。如果要将它们用作文字字符,则必须将它们转义为实体,例如 < 和 &。 比如你想写关于“AT&T”的内容,你需要写“AT&T”。还需要在 URL 中转义&字符,如果你想链接到: ...&q=larry+bird必须将 URL 编码为: ...&q=larry+bird才能放到标签 href 属性中,这很容易被忘记。Markdown 允许你直接使用这些符号,并帮你自动处理所有必要的转义。如果你使用&符号作为 HTML 实体的一部分,它将保持不变,否则它将被翻译成&。 因此,如果想在文章中包含版权符号,可以这样写: © 印迹说(符号代码 ©)Markdown 不会对它做修改,但如果你写: AT&TMarkdown 会将其翻译为: AT&;T类似地,由于 Markdown 支持行内 HTML,如果你使用尖括号<作为 HTML 标签的分隔符,Markdown 不会对其做任何转义,但如果你这样写: 4 < 5Markdown 会将其翻译为: 4 < 5另外要注意的是,在 Markdown 内联和块元素中,<尖括号和&符号始终会自动编码。这使得使用 Markdown 编写 HTML 代码变得容易(在 HTML 语法中,你要手动把所有的 < 和 & 都转换为 HTML 实体。) 自动 URL 链接 许多 Markdown 编辑器会自动将 URL 或者 email 地址转换为链接,输入网址时,即使没使用尖括号<,Markdown 编辑器也会自动转为可点击链接。 https://mp.weixin.qq.com如果想禁用自动链接 URL,则可以通过反引号`来删除该链接。 `https://mp.weixin.qq.com`脚注 脚注用于添加注释和参考来源,添加脚注时,带有脚注的上标数字会出现在添加脚注参考的位置。这样做的好处是,能保持文档的整洁性。 创建方法是,在方括号内[^1]添加插入符号和标识符,标识符可以是数字或单词,但不能包含空格或制表符。 [^1]: This is the first footnote. [^2]: This is the second footnote.Markdown 语法的最大灵感来源是纯文本电子邮件的格式,旨在尽可能地易于阅读和易于编写。因此,Markdown 的语法完全由标点符号组成,这些标点符号经过精心挑选,以使其看起来像它们的意思。 由于公众号并不能完全兼容 Markdown 所有标记语法,导致一些演示效果与实际效果有细微差异,还由于不能插入外部链接,有一些语法不能完整呈现,不过并不影响作为 Markdown 备忘录学习。
-
PHP 8.4 新特性:属性钩子实用指南 (2025) PHP 8.4 引入了一项名为 Property Hooks 的创新功能,它将彻底改变开发者处理类属性的方式。这种突破性的特性以更优雅、更强大的语法替代了传统的 getter 和 setter 方法,不仅简化了属性访问控制,还确保了代码的简洁性和可维护性。 图片 理解属性钩子: 属性钩子是一种用于拦截属性访问和修改的特殊方法。相比于传统的 getter 和 setter,属性钩子提供了一种更直接、更直观的方式来管理类属性,并且内置了类型安全和验证机制,能更流畅地控制属性交互。 属性钩子的主要优势: 简化语法: 消除冗余的 getter 和 setter 方法,代码更简洁。 增强封装: 对属性访问进行更严格的控制,提高代码安全性。 提升类型安全: 内置类型检查机制,减少运行时错误。 优化性能: 通过更高效的验证方式,实现更快的属性访问。 实际应用 让我们通过一个实际的例子来深入了解属性钩子的强大之处。假设我们有一个 BankAccount 类,需要对账户余额进行复杂的管理: class BankAccount { public get float $balance { return $this->_balance * $this->exchangeRate; } public set float $balance { if ($value < 0) { throw new InvalidArgumentException('Balance cannot be negative'); } $this->_balance = $value; } private float $_balance = 0; private float $exchangeRate = 1.0; }在这个例子中,balance 属性的属性钩子展示了几个关键特性: 自动货币转换: 通过 exchangeRate 实现自动货币转换。 余额验证: 防止出现负余额,保证数据有效性。 类型安全: 确保余额始终为浮点数类型。 简洁易读: 简化了属性访问方式,代码更清晰。 真实场景:电子商务产品定价管理 另一个常见的应用场景是在电子商务应用中管理产品的价格: class Product { public get float $price { return $this->basePrice * (1 - $this->discount); } public set float $price { if ($value <= 0) { throw new InvalidArgumentException('价格必须为正数'); } $this->basePrice = $value; } private float $basePrice = 0; private float $discount = 0; } // 使用示例 $product = new Product(); $product->price = 99.99; // 设置基本价格 echo $product->price; // 计算带折扣的价格这个例子展示了属性钩子如何: 实现复杂的定价计算逻辑 强制执行业务规则(例如:确保价格为正数) 提供简洁明了的价格操作接口 属性钩子相比传统方法的优势 传统的 getter 和 setter 方法常常导致: 代码冗长且重复。 可读性降低。 验证逻辑可能不一致。 方法调用会产生额外的性能开销。 属性钩子通过以下方式解决了这些问题: 提供更简洁的语法。 集中管理属性访问逻辑。 维持严格的类型安全。 提供直接的属性访问方式,如同访问普通属性一样。 最佳实践 在实现属性钩子时,请注意以下几点: 适用于复杂属性逻辑:仅在需要复杂处理时使用属性钩子。 确保类型安全:务必进行类型检查,保证数据类型正确。 实施全面验证:对属性值进行充分的验证,防止非法数据。 保持钩子实现简洁明了:保证钩子函数的逻辑清晰,易于理解和维护。 结论 PHP 8.4 中引入的属性钩子,是面向对象编程领域的一项重大进步。它提供了一种更优雅、更强大的类属性管理方式,帮助开发者编写出更易于维护、更具可读性以及更加健壮的代码。 需要注意的是,任何新的语言特性都需要合理运用。属性钩子并非要完全取代传统的 getter 和 setter 方法,而是作为 PHP 开发工具箱中的一个强有力补充,需要开发者根据实际场景灵活选择。
-
16 个 JavaScript 简写神技,代码效率提升 60%! JavaScript 是一门强大且灵活的语言,拥有丰富的特性和语法糖。分享下 16 个最常用的 JavaScript 的简写技巧,掌握它们可以让我们编写出更简洁、更优雅的代码,并显著提升开发效率(增加摸鱼时间)。 图片 1. 三元运算符简化条件判断 // 传统写法 let result; if (someCondition) { result = 'yes'; } else { result = 'no'; } // 简写方式 const result = someCondition ? 'yes' : 'no';2. 空值合并运算符 // 传统写法 const name = user.name !== null && user.name !== undefined ? user.name : 'default'; // 简写方式 const name = user.name ?? 'default';3. 可选链操作符 // 传统写法 const street = user && user.address && user.address.street; // 简写方式 const street = user?.address?.street;4. 数组去重 // 传统写法 function unique(arr) { return arr.filter((item, index) => arr.indexOf(item) === index); } // 简写方式 const unique = arr => [...new Set(arr)];5. 快速取整 // 传统写法 const floor = Math.floor(4.9); // 简写方式 const floor = ~~4.9;6. 合并对象 // 传统写法 const merged = Object.assign({}, obj1, obj2); // 简写方式 const merged = {...obj1, ...obj2};7. 短路求值 // 传统写法 if (condition) { doSomething(); } // 简写方式 condition && doSomething();8. 默认参数值 // 传统写法 function greet(name) { name = name || 'Guest'; console.log(`Hello ${name}`); } // 简写方式 const greet = (name = 'Guest') => console.log(`Hello ${name}`);9. 解构赋值 图片 10. 字符串转数字 图片 11. 多重条件判断 图片 12. 快速幂运算 图片 13. 对象属性简写 图片 14. 数组映射 图片 15. 交换变量值 图片 16. 动态对象属性 // 传统写法 const obj = {}; obj[dynamic + 'name'] = value; // 简写方式 const obj = { [`${dynamic}name`]: value };欢迎补充。
-
关于手游开挂的一些经验总结 所谓的安卓过环境 我就这么和你说吧,如果过环境有用,为什么还这么多人三方,运行环境七天了,如果过环境有用的话,为什么都没人敢用原版面具+过环境开挂玩,谁敢用原版面具,很搞笑,真的。 真的很搞笑,为什么现在都让你过环境,因为,他们想挣你过环境的💰,炒起来的 本来过环境就是针对银行软件,和支付宝人脸什么的而已,游戏又不检测这个,暗区除外 全过环境,已经属于针对游戏做出操作 无限高风险都有可能,过吧,高风险就笑死 个别人会酷酷高风险,不是所有人 还有,过环境目前只是会影响高风险 不会十年,后续就不知道了, 始终是对和平精英继续操作了,嘻嘻 还有全过环境的高风险,好像是有一次高风险就得刷机,不然很容易继续高风险 三方原因↓ 外挂=面具 四个原因,面具占第一,外挂第二 高风险原因↓ 外挂=全过环境=行为=乱杀数据涨太快 外挂占第一,其他的都差不多 掉号问题总结 隔离问题 被迫下线禁网十分钟后再上去发现隔离七天 隔离这个问题百分之八十就是实名黑了,就是你实名的号封号了,就有几率导致其他实名的号会几率隔离 特别是小号,实名黑的人压根不能玩小号,只能去买号玩, 还有一种情况就是这个账号问题,无解,说不定什么时候自己就好了 还有一种情况就是设备黑了导致的,刷机就可以解决,这种百分之十的几率是,是这个原因的几率不大 高风险问题 突然换设备或者经常换设备登录有几率会高风险 突然异地登录也有几率高风险 太久没玩的账号突然去玩还杀很多也有几率高风险 举报太多杀太多也也有几率高风险 之前数据太低你一下子杀太多kd涨太快也也有几率高风险 总而言之,系统感觉你不对劲,就有可能高风险 不开挂一样百分百也会高风险,只要你符合上面 高风险分两种 一种是太久没玩或者kd突然涨太快,这种百分之99都会解封 一种就是举报太多了送你去巡查,这种就看你演技了 具体是哪种可以腾讯游戏安全中心查询,高风险冻结就是巡查,表现分异常就是第一种 第三方封号一个月 这个问题很少情况是因为越狱问题导致的,但是你不能说没有 大部分情况就是检测到了你桌面有外挂有异常或者说检测到了你后台有外挂有异常 第三方这个问题是没法解决的,这个几率不大,就算你三方也不会十年,一万次三方也只是三方 这种没啥事的,不会有影响,就是游戏检测到了不对劲,他没检查到你开挂了,只是检测到了你有这些软件 运行环境七天 这种情况的话实际上就是检测到了你使用外挂,给你一次机会,下次就是十年,不是说每个号都会有一次机会,看脸,大部分都会有一次机会 意思就是只有十年和运行环境才是属于游戏知道了你开挂,哦对还有巡查哦,演戏哦 安卓买什么 手机= 真我,红魔,一加,魅族,小米(小米不建议买麻烦) 平板= 一加平板pro,拯救者y700三代, 二代也行,只能90帧, 小米(小米不建议买麻烦又掉帧又不跟手) 就说那么多,其他的买了设备再说 设备还没有就别问我了,浪费时间 见一面少一面 - 洋澜一" url="https://txmov2.a.kwimgs.com/upic/2025/02/03/21/BMjAyNTAyMDMyMTAyMDlfOTAzODE5Njk5XzE1NTg3NzA1MTQwOF8yXzM=_b_Bc6056a64dc7b8b12af7909e181b5f87a.mp4" cover="https://p4-ad.adukwai.com/upic/2025/02/03/21/BMjAyNTAyMDMyMTAyMDlfOTAzODE5Njk5XzE1NTg3NzA1MTQwOF8yXzM=_B942e3a027faa16ccc6ca39e0add26802.jpg" theme="#409eff" lrc="" lrcType="0" loop="none" autoplay="1" storage="0" autotheme="1
-
致全体绿玩的一封信 外挂是工具,开挂是手段,手段是能力,作弊是智慧。 没挂就别叫,有挂就得开(开挂已是无敌路,何须再用智商补。 开挂有路你不走,绿玩无门你自来投。外挂只是最强的外设,强者总会被针对。 练枪是小径,自瞄是大道,意识会出错,透视秒全场,不要问为什么开挂,因为你已经习惯愚蠢。 开挂者人均天资聪颖,因为真正的高手,都善于走捷径,我们在熙熙攘攘的生活中享受外挂,当绿玩被无情击败,才会明白,他们离成功只差一张板子。 昔海无涯回头是挂,外挂就是最踏实的那条路,趁现在开挂还来得及。 当你练习了一辈子,站在山巅,才发现,外挂在对着你笑。 将盗行DJ - 花粥/马雨阳" url="https://txmov2.a.kwimgs.com/upic/2024/12/12/20/BMjAyNDEyMTIyMDMyNDlfNDIyOTkyMzM5Nl8xNTA5ODY1NzYyNjNfMl8z_b_Bf986c37e8e733647153f91d97251b543.mp4" cover="https://p4-ad.adukwai.com/upic/2024/12/12/20/BMjAyNDEyMTIyMDMyNDlfNDIyOTkyMzM5Nl8xNTA5ODY1NzYyNjNfMl8z_ccc_Bbdea1462acc4ee66c40ccb549a7c9b6c.jpg" theme="#409eff" lrc="" lrcType="0" loop="all" autoplay="1" storage="0" autotheme="1
-
掌握这 8 个 JavaScript 的 Promise 并发控制技巧,性能大幅提升 Promise 已经成为 JavaScript 里处理异步操作的标准方式。然而,当我们需要同时处理多个异步任务时,如何有效地控制 Promise 的并发,就成为了一个影响性能和用户体验的关键问题。 假设,你需要同时请求 100 个接口来获取数据。如果一股脑地发起所有请求,可能会导致以下问题: 浏览器并发限制:浏览器对同一域名的并发请求数量有限制(通常是 6-8 个)。过多的请求会被阻塞,导致页面加载缓慢 服务器压力过大:大量并发请求可能会给服务器带来巨大的压力,导致响应变慢甚至崩溃 资源竞争:多个异步任务同时访问共享资源(例如数据库连接、文件等),可能会导致资源竞争和死锁 用户体验差:页面长时间处于加载状态,用户体验极差 因此,我们需要对 Promise 的并发进行控制,在保证任务执行效率的同时,避免对系统资源造成过大的压力。 Promise.all:并行执行,统一返回 Promise.all 接收一个 Promise 数组作为参数,并行执行所有 Promise,并在所有 Promise 都 fulfilled 后,返回一个包含所有结果的数组。 const promise1 = Promise.resolve(1); const promise2 = Promise.resolve(2); const promise3 = Promise.resolve(3); Promise.all([promise1, promise2, promise3]) .then(results => { console.log(results); // 输出:[1, 2, 3] });适用场景: 多个异步任务之间没有依赖关系,可以并行执行。 注意: 如果其中任何一个 Promise 被 rejected,Promise.all 会立即 rejected,并且只返回第一个 rejected 的原因。 Promise.allSettled:并行执行,返回所有状态 Promise.allSettled 与 Promise.all 类似,也是并行执行所有 Promise,但它会等待所有 Promise 都 settled(fulfilled 或 rejected),并返回一个包含所有 Promise 状态和结果(或原因)的数组。 const promise1 = Promise.resolve(1); const promise2 = Promise.reject("Error"); const promise3 = Promise.resolve(3); Promise.allSettled([promise1, promise2, promise3]) .then(results => { console.log(results); /* 输出: [ { status: 'fulfilled', value: 1 }, { status: 'rejected', reason: 'Error' }, { status: 'fulfilled', value: 3 } ] */ });适用场景: 需要获取所有 Promise 的执行结果,无论它们是 fulfilled 还是 rejected。 Promise.race:并行执行,谁快用谁 Promise.race 接收一个 Promise 数组作为参数,并行执行所有 Promise,只要其中任何一个 Promise settled(fulfilled 或 rejected),Promise.race 就会返回该 Promise 的结果(或原因)。 图片 适用场景: 只需要获取最快完成的 Promise 的结果,例如设置请求超时。 Promise.any (ES2021):并行执行,返回第一个 fulfilled Promise.any 接收一个 Promise 数组作为参数,并行执行所有 Promise,只要其中任何一个 Promise fulfilled,Promise.any 就会返回该 Promise 的结果。如果所有 Promise 都 rejected,则返回一个 AggregateError。 图片 适用场景: 需要获取第一个成功的 Promise 的结果。 自定义并发控制函数:限制最大并发数 Promise.all 等方法虽然可以并行执行 Promise,但无法控制并发数量。我们可以自己实现一个函数来限制最大并发数。 图片 使用示例: 图片 原理: tasks: 一个包含任务函数的数组,每个任务函数返回一个 Promise。 limit: 最大并发数。 results: 存储所有任务的结果。 running: 存储当前正在执行的任务(Promise)。 current: 指向下一个要执行的任务。 while 循环:只要还有任务未执行或有任务正在执行,就继续循环。 if 条件:如果当前正在执行的任务数量小于 limit 且还有任务未执行,则取出下一个任务执行,并将其添加到 running 数组中。 task.then():监听任务完成,将结果添加到 results 数组,并将任务从 running 数组中移除。 await Promise.race(running):如果当前正在执行的任务数量已达到 limit,则等待任意一个任务完成。 Promise.all(results): 等待所有任务执行, 并返回结果。 使用第三方库:p-limit、async-pool 等 有一些成熟的第三方库可以更方便地实现 Promise 并发控制,例如: p-limit: 一个轻量级的 Promise 并发控制库。 图片 async-pool: 一个支持多种并发策略的 Promise 并发控制库。 使用 Generator 函数和 yield 关键字 Generator 函数可以暂停和恢复执行,结合 yield 关键字,可以实现更细粒度的并发控制。 async function* taskGenerator(tasks) { for (const task of tasks) { yield task(); } } async function runTasks(tasks, limit) { let pool = []; let results = []; for await (let result of taskGenerator(tasks)) { pool.push(result); results.push(result); if (pool.length >= limit) { await Promise.race(pool); pool = pool.filter(p => p.status != 'fulfilled' && p.status != 'rejected') // 手动维护 } } return Promise.all(results) }使用消息队列 对于非常大量的异步任务, 且允许一定的延迟, 可以使用消息队列(例如 RabbitMQ, Kafka 等), 将任务放入队列, 然后由多个消费者并行处理. 欢迎补充。
-
小米手机一键关闭广告,比新手机还丝滑 小米手机的性价比高,但广告也不少。不过好在这些广告都能关,我整理了澎湃 OS 最新的关闭广告教程,快操作起来吧! 一、关闭系统工具广告 打开设置 → 小米账号 → 关于小米账号 → 系统广告 → 关闭系统广告工具 图片 二、关闭应用资源推荐 打开设置 → 应用设置 → 应用管理 →“右上角…”→ 设置 → 关闭资源推荐 图片 三、关闭垃圾短信推送 打开信息 → 右上角设置 → 高级设置 → 关闭允许 WAP 推送 图片 四、关闭今日推荐 随便打开一个桌面文件夹 → 点文件夹名称 → 关闭今日推荐 图片 五、关闭系统个性化广告推荐 打开设置 → 安全 → 更多安全设置 → 公开服务 → 关闭个性化广告推荐 图片 六、关闭搜索广告并开启网站广告过滤 桌面搜索框点三个点 → 设置 → 首页展示模块 → 关闭为你推荐/热搜榜单 → 返回搜索设置 → 确认并开启网站广告过滤 图片 七、关闭负一屏广告 打开设置 → 桌面 → 负一屏 → 关闭推荐卡片/热门活动 图片 八、关闭天气广告推送 打开天气 → 上角设置 → 用户体验计划 → 关闭天气卡片和内容推广 图片 九、关闭手机管家广告推送 打开手机管家 → 右上角设置 → 隐私设置 → 关闭个性化推荐 图片 十、关闭应用商店广告推送 打开应用商店 → 我的 → 右上角设置 → 隐私设置 → 关闭个性化服务 图片 十一、关闭主题壁纸广告推送 打开主题壁纸 → 我的 → 右上角设置 → 隐私设置 → 关闭个性化推荐 图片 十二、开启浏览器广告过滤 打开自带浏览器 → 右上角关闭快捷网站/全网热榜浏览器下面三条杠 → 设置 → 隐私防护 → 开启广告过滤 图片 十三、关闭日历广告推送 打开日历 → 右上角设置 → 用户体验计划 → 关闭内容推广 图片 快去试试吧,有什么问题欢迎留言讨论。