我们先思考两个问题,如下:
为什么会存在同步和异步的概念?
我们的JavaScript是单线程的,也就是我们的工作流水线的只有一条。如果我们的任务全放在流水线上,其中一个任务出现问题就会阻塞后面的任务,导致我们的工作流水线卡住。因此为了更加高效合理利用这条流水线,在JavaScript中出现了同步与异步的概念。
同步与异步任务如何在一条流水线上工作?
同样是一条流水线。我们的有不同的产品,有的产品能瞬间完成,有的产品需要耗费大量时间才能完成。那么我们给这堆产品分为两类,能瞬间完成的产品先放入流水线前面,而需要耗费大量时间的产品则放在流水线后面。将所有的产品按顺序从流水线上执行。即使后面有部分产品制作很慢,但我们流水线前面的大部分产品都能顺利完成。也就是说,我们能够及时交付大部分的产品,让老板基本满意就足够了。后面的产品我们再慢慢做也不迟。
同步
同步任务:我们的任务不会造成流水线阻塞,瞬间就能完成。那我们直接把这些任务定义为同步任务。
同步事件:new Promise()、async关键字、console对象方法
异步
异步任务:我们的任务可能会造成流水线阻塞,需要时间才能完成。那我们直接把这些任务定义为异步任务。
异步事件:我们先不介绍异步事件,因为异步事件又分为微任务与宏任务。我们下面再介绍。
微任务事件:Promise.then()、await 后面的语句、queueMiscrotask、MutationObserver、process.nextTick( node.js环境 )[ 微任务中最先执行 ]
宏任务事件:setTimout() 和 setInterval()、<script>脚本、I/O、UI交互事件、setImmediate( node.js环境 )[ 宏任务中最后执行 ]
注意:异步事件分为微任务和宏任务,其中微任务优先于宏任务执行。
执行栈:同步代码会首先归类到此处待执行。按照代码的书写顺序(上到下)入栈。
微任务队列:异步中的微任务代码归类到此处。按照代码的书写顺序(上到下)入队。当执行栈为空时,微任务会出队进入执行栈。
宏任务队列:异步中的宏任务代码归类到此处。按照代码的书写顺序(上到下)入队。当微任务队列为空时,宏任务会出队进入执行栈。
我们采用验证法做几道题
第一道如下:
console.log(1)
setTimeout(() => {
console.log(2)
setTimeout(() => {
console.log(3)
}, 1000)
}, 1000)
new Promise((resolve, reject) => {
console.log(4)
resolve(5) // 之后会调用 then 方法
console.log(6)
}).then((resolve, reject) => {
console.log(resolve)
})
function add(a, b) {
return a + b
}
async function foo() {
console.log(7)
let num = await add(4, 4)
console.log(9)
return num
}
foo().then((num) => {
console.log(num)
})
console.log(10) // 1 4 6 7 10 5 9 8 2 3
以上代码没有出现宏任务嵌套微任务,微任务嵌套宏任务的情况。那么我们可以按编号(对应的输出语句)直接对执行栈、微任务和宏任务分类如下:
第一次分析执行栈(同步任务):1 4 6 7 10
第二次分析微任务:5 9 8
第三次分析宏任务:2 3
然后我们按执行顺序将答案组合在一起。最终答案:1 4 6 7 10 5 9 8 2 3。
注意:以上分析方法只能应对异步函数无嵌套的情况。
接下来我们增加难度,宏任务嵌套微任务,微任务嵌套宏任务。第二题如下:
console.log(1)
setTimeout(() => {
console.log(2)
new Promise((resolve, reject) => {
console.log(3)
resolve(4)
}).then((resolve, reject) => {
console.log(resolve)
})
console.log(5)
}, 1000)
console.log(6)
new Promise((resolve, reject) => {
console.log(7)
resolve(8)
setTimeout(() => {
console.log(9)
}, 1000)
}).then((resolve, reject) => {
console.log(resolve)
})
console.log(10) // 1 6 7 10 8 2 3 5 4 9
以上代码出现了宏任务嵌套微任务,微任务嵌套宏任务的情况。
提示:外部(全局作用域)的代码可以按任务执行顺序分析,异步函数内部其实也可以按照我们的任务执行顺序分析。其分析过程是一样的。
最终答案:1 6 7 10 8 2 3 5 4 9。还有很多特例,可自行编写异步函数测试。总结方法
分析方法:先对代码进行事件分类,然后分别放入对应类型的三个地方(执行栈、微任务队列和宏任务队列)再按照我们的执行顺序,发生异步函数嵌套情况时,也可以对其内部应用这套规则解决。
任务执行顺序如下:
参考
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
是否有简单的方法来更改默认ISO格式(yyyy-mm-dd)的ActiveAdmin日期过滤器显示格式? 最佳答案 您可以像这样为日期选择器提供额外的选项,而不是覆盖js:=f.input:my_date,as::datepicker,datepicker_options:{dateFormat:"mm/dd/yy"} 关于ruby-on-rails-事件管理员日期过滤器日期格式自定义,我们在StackOverflow上找到一个类似的问题: https://s
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候
动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、
我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).
我是Ruby的新手,有些闭包逻辑让我感到困惑。考虑这段代码:array=[]foriin(1..5)array[5,5,5,5,5]这对我来说很有意义,因为i被绑定(bind)在循环之外,所以每次循环都会捕获相同的变量。使用每个block可以解决这个问题对我来说也很有意义:array=[](1..5).each{|i|array[1,2,3,4,5]...因为现在每次通过时都单独声明i。但现在我迷路了:为什么我不能通过引入一个中间变量来修复它?array=[]foriin1..5j=iarray[5,5,5,5,5]因为j每次循环都是新的,我认为每次循环都会捕获不同的变量。例如,这绝对
这是我在ActiveAdmin中的自定义页面ActiveAdmin.register_page"Settings"doaction_itemdolink_to('Importprojects','settings/importprojects')endcontentdopara"Text"endcontrollerdodefimportprojectssystem"rakedataspider:import_projects_ninja"para"OK"endendend我想做的是,当我单击“导入项目”按钮时,我想在Controller中执行rake任务。但是我无法访问该方法。可能是什
例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果