「JavaScript」同步、异步、回调执行顺序之经典闭包setTimeout分析
来源:互联网 发布:伊丽莎白雅顿天猫 知乎 编辑:程序博客网 时间:2024/06/06 12:27
聊聊同步、异步和回调
同步,异步,回调,我们傻傻分不清楚,
有一天,你找到公司刚来的程序员小T,跟他说:“我们要加个需求,你放下手里的事情优先支持,我会一直等你做完再离开”。小T微笑着答应了,眼角却滑过一丝不易觉察的杀意。
世界上的所有事情大致可以分为同步去做和异步去做两种。你打电话去订酒店,电话另一边的工作人员需要查下他们的管理系统才能告诉你有没有房间。
这时候你有两种选择:一种是不挂电话一直等待,直到工作人员查到为止(可能几分钟也可能几个小时,取决于他们的办事效率),这就是同步的。
另一种是工作人员问了你的联系方式就挂断了电话,等他们查到之后再通知你,这就是异步的,这时候你就可以干点其他事情,比如把机票也定了之类的
计算机世界也是如此,我们写的代码需要交给cpu去处理,这时候就有同步和异步两种选择
js是单线程的,如果所有的操作(ajax,获取文件等I/O操作<node>)都是同步的,遇到哪些耗时的操作,后面的程序必然被阻塞而不能执行,页面也就失去了响应,
因此js采用了事件驱动机制,在单线程模型下,使用异步回调函数的方式来实现非阻塞的IO操作,
那么什么是异步任务呢?(参考阮一峰老师《JavaScript运行机制》)
异步任务也就是 指主线程(stack栈)运行的过程中,当stack空闲的时候,主线程对event queque(队列)
轮询(事实上一直在轮询)后,将异步任务放到stack
里面进行执行;
(上图转引自Philip Roberts的演讲《Help, I'm stuck in an event-loop》))
简单的说,如果我们指定过回调函数,那么当事件发生时就会进入事件队列,等待主线程的(stack)空闲的时候,就会对event queue
里面的回调读取并放到stack里面执行
我们经常说的可能是异步回调(当然也有同步回调),所以也就并不难理解,回调和异步之间其实并没有直接的联系,回调只是异步的一种实现方式,
通过这样的event loop我们其实可以分析出三者的执行顺序,即 同步 > 异步 > 回调
经典闭包setTimeout分析
今天同学问了我一个问题,我一看是一道经典的面试题,问题如下:
简单的这个问题改一下:
1 for (var i = 0; i <= 5; i++) {2 setTimeout(function() {3 console.log( i );4 }, i*1000);5 console.log( ' i : ' , i );6 }7 8 console.log( i );
相信我们很多人都遇到过这个问题,心中或许都有答案:
那么为什么并不是入门者心中所想要的结果嘞?
首先我们来梳理一下,第一部分event loop图片很直观的体现:"任务队列"可以放置异步任务的事件,也可以放置定时事件(setTimeout和setinterval),即指定某些代码在多少时间之后执行;
1、首先我们先来看一下他的主体结构: for循环的第一层是setTimeout函数,setTimeout函数中使用了一个匿名(回调)函数
2、还记的我们之前总结的执行顺序:同步 > 异步 > 回调 吧!
1)for循环和外层的 console.log()是同步的,setTimeout是回调执行,
所以按照执行顺序,先执行for循环,然后进入for循环中,他发现了一个setTimeout()回调(进入event queque事件队列,等待stack栈为空后读取并放入栈中后执行),这时候他并不会等待
而是继续执行 --> for循环内部的 console.log( ' i : ' , i ) --> for循环外部的console.log( i ) ,然后才会去执行"任务队列"中的回调函数;
我们在来用这个例子尝试一下上面的event loop图,更加直观的感受一下:
那么接下来可能会问怎么解决这个问题呢?我想最简单的当然是let语法了,
1 for (let i = 0; i <= 5; i++) {2 setTimeout(function() {3 console.log( i );4 }, i*1000);5 console.log( ' 1 : ' , i );6 }7 8 console.log( i );
我们都知道es5中变量作用域是函数,而es6却可以使用let声明一个具有块级作用域的i,在这里也就是for循环体;
在这里let本质上就是形成了一个闭包,那么写成es5的形式其实等价于:
1 var loop = function (_i) { 2 setTimeout(function() { 3 console.log( _i); 4 }, _i*1000); 5 console.log('2:',_i)
6 };
7
8 for (var _i = 0; _i <= 5; _i++) {
9 loop(_i);
10 }
总结
到这里,我们就完成了从同步、异步、回调的机制分析 到 setTimeout的经典案例的分析,JavaScript博大精深,我们需要了解他的机制去深入去挖掘他。
出处:http://www.cnblogs.com/okaychen/
github:okaychen
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留转载声明
- 「JavaScript」同步、异步、回调执行顺序之经典闭包setTimeout分析
- JavaScript同步、异步、回调执行顺序之经典闭包setTimeout面试题分析
- JavaScript同步、异步、回调执行顺序之经典闭包(setTimeout面试题分析)
- JavaScript同步、异步、回调执行顺序之setTimeout面试题分析
- JavaScript同步、异步、回调执行顺序分析
- 【JavaScript】JavaScript同步、异步、回调的执行顺序
- setTimeout的“异步”,执行顺序
- 理解JavaScript 执行机制及异步回调(setTimeout/setInterval/Promise)
- Javascript异步编程之setTimeout与setInterval
- Javascript setTimeout(0),闭包
- setTimeout异步执行
- JavaScript异步和单线程经典的例子setTimeout
- JavaScript之执行顺序
- JavaScript同步与异步之异步进化史
- Javascript的setTimeout()闭包特性
- javascript 执行顺序和闭包典型应用
- setTimeout “不执行”和异步
- .NET 同步与异步 之 警惕闭包(十)
- MySql中索引学习
- 【wxPython】wxPython获取系统字体
- 如何做卓有成效的程序员
- GDB跟踪调试linux-3.18.6内核
- 第十一周项目三——图遍历算法实现
- 「JavaScript」同步、异步、回调执行顺序之经典闭包setTimeout分析
- java并发编程之--CountDownLatch
- 【持续更新】个人开发中常用linux命令
- SpringCloud 服务发现组件 Eureka的初步学习
- 第十周项目三
- 【第八周】项目1-建立顺序串的算法库
- Django-restframework13 ViewSets
- cglib动态代理
- ECShop自定义title标题