for循环+setTimeout(JavaScript的同异步 上)

js的同步异步理解

怎么出现的

个人理解:
JavaScript是一门单线程的语言,在同一个时间只能做一件事;
同个时间有多个任务的话,排队,前一个任务执行完,才会执行下一个任务;
如果前一个任务的执行时间很长,比如文件的读取操作或ajax操作,后一个任务就不得不等着。
位置:
同步任务:主线程按序执行
异步任务:任务(事件)队列里,先进先出

执行逻辑

(1)所有同步任务都在主线程上执行,行成一个执行栈
(2)主线程之外,还存在一个任务队列,只要异步任务有了结果,就会在任务队列中放置一个事件
(3)一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,
看看里面还有哪些事件,那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行
(4)主线程不断的重复上面的第三步

哪些是异步的

setTimeout 和 setInterval   ajax   Promise

for循环 + setTimeout

示例一:

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}
// 1 秒之后,同时输出 5 个 5。
解释:因为 同步优先于异步优先于回调,所以先执行i递增到5,
setTimeout 的回调全部塞入了事件队列中,然后 1 秒后一起执行了
  1. 问:为什么结果不是 1 2 3 4 5 (考察作用域)
回答:
因为 setTimeout 的 console.log(i);的i是 var 定义的,是函数级的作用域,不属于 for 循
环体,属于 global全局。等到 for 循环结束,i 已经等于 5 了,这个时候执行 setTimeout 
的五个回调函数,i 去向上找作用域,只能找到 global下 的 i,即 5。所以输出都是 5。
  1. 问:如何输出12345

-解1: 改变作用域

for (let i = 0; i < 5; i++) {   //let 代替 var
  setTimeout(function (){
    console.log(i); 
   },1000); 
}
解释:
let 块作用域,每次执行都引用到 for 循环下的i,
在 setTimeout 未执行前都不会被释放。
  1. 解2:立即执行函数(闭包)
for (var i = 0; i < 5; i++) { 
	console.log(1);
  (function(i){   //立刻执行函数 
    setTimeout(function (){
    	console.log(2);
      console.log(i); 
     },1000); 
  })(i); 
    console.log(3);
}
// 1 3 1 3 1 3 1 3 1 3 2 0 2 1 2 2 2 3 2 4 
解释:
立刻执行函数:i每一次循环生成的值 保存在立刻执行函数中的作用域
但是由上面打印所知:不是同步,依旧是异步
  1. 解3:setTimeout处理
for (var i = 0; i < 5; i++) { 
console.log(1);
setTimeout((function(i) { 
console.log(2);
 console.log(i); 
})(i), i * 1000); 
console.log(1);
}
// 结果:1,2,0,1,1,2,1,1,1,2,2,1,·······同步执行的 为啥
解释:
setTimeout可以接受函数或者字符串作为参数,
而给setTimeout传递了一个立即执行函数,该立即执行函数是undefined ,
也就是说等价于setTimeout(undefined, ...),不起作用。立即执行函数会立即执行
  1. 思考:可不可以让setTimeout同步执行,出现打印一次停1秒中
  • 1、递归实现
var i = 1
function time(i){
	if(i>5){
		clearTimeout(t)
		return
	}
	var t =  setTimeout(function () {
      console.log(i);
      time(i+1)
     }, 1000);
}
time(1)
  • 2、使用回调函数
function time1(callback) {
    let timer1 = setTimeout(function() {
        console.log("0");
        callback();
    }, 3000)
}
time1(function () {
    let timer2 = setTimeout(function() {
        console.log("1");
    }, 2000);
});
//0 3s后输出
//1 5s后输出
在JavaScript中一个函数可以作为另一个函数的参数,
这个作为参数的函数就叫回调函数,以回调函数作为参数的函数叫做主函数
需要注意的很重要的一点是回调函数并不会马上被执行。
它会在包含它的函数内的某个特定时间点被“回调”
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值