js中的同步、异步、promise

javascript语言是一门“单线程”的语言(javascript就像一条流水线,仅仅是一条流水线而已,要么加工,要么包装,不能同时进行多个任务和流程)。

同步和异步的差别就在于这条流水线上各个流程的执行顺序不同。

同步:提交请求 — 等待服务器处理 — 处理完毕返回,(这个期间浏览器不能干任何事)。

同步:发送方付出数据后,等待接收方响应后才发下一个数据包的通讯方式。
异步:发送方发出数据后,不等待接收方的响应,接着发送下一个数据包的通讯方式。

最基础的异步是 setTimeout 和 setInterval 函数
可以简单地理解为:可以改变程序正常执行顺序的操作就可以看成是异步操作。

demo1:

<script type="text/javascript">  
        console.log( "1" );  
        setTimeout(function() {  
            console.log( "2" )  
        }, 0 );  
        setTimeout(function() {  
            console.log( "3" )  
        }, 0 );  
        setTimeout(function() {  
            console.log( "4" )  
        }, 0 );  
        console.log( "5" );  
</script>  

以上代码会打印出 1, 5,2,3,4;

demo2:(有考察到异步、作用域、闭包)

for (var i = 0; i < 5; i++) { 
  setTimeOut(() => {   // 同步注册回调函数到 异步的 宏任务队列。
     console.log(i)   // 执行此代码时,同步代码for循环已经执行完成
  }, 1000)
 }

第一眼看上去 大家肯定会觉得答案为:0,1, 2,3, 4;
结果当我们在控制台打印后发现答案是 5次5;

原因:
1、setTimeOut 是异步执行函数,1000后执行。
2、在for循环中的 i 每次都是执行 setTimeOut 这个函数,并没有执行里面的 function(闭包函数)。
3、setTimeOut 里面的 function 是由 setTimeOut 的定时触动的,也就是1000ms之后才执行。
4、也就是说 i 从 0 ~ 5时,一共执行了 5次 的 setTimeOut 函数,此时最后的 i 值已经是5了。
5、由于 for 的循环函数远远小于 10秒,10秒后 闭包函数开始执行时,i 值已经是5了。所以打印了5个5。

思考:
为什么把 var 换成 let ,结果输出为:0,1, 2,3, 4

var 和 let 的区别?

  • var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象;
  • let 声明的变量,其作用域为该语句所在的代码块内,不存在变量提升;
  • let 不允许在相同作用域内,重复声明同一个变量。
{
  let a = 111;
  var b = 222;
}
a // Uncaught ReferenceError: a is not defined
b // 222
for (var i = 0; i < 5; i++) { 
     console.log(i)  // 0,1,2,3,4
 }
 console.log(i); // 5
for (let i = 0; i < 5; i++) { 
     console.log(i)   // 0,1,2,3,4
 }
 console.log(i); //ReferenceError: i is not defined

如果不将 var 修改成 let 还能用什么方法输出 0,1,2,3,4 呢 ?

for(var i = 0; i < 5; i++) {
	(function name(i) {
		setTimeout(() => {
			console.log(i)
		}, i * 1000)
	})(i)
}

如果想输出 0、1、2、3、4、5 ?可以用 es6 中的 Promise:

let arr = [];
const promise = (i) => new Promise((resolve) => {
	setTimeout(() => {
		arr.push(i);
		console.log(i);
		resolve();
	}, 1000 * i)
});

for (var i = 0; i < 5; i++) {
	arr.push(promise(i));
};

Promise.all(arr).then(() => { // Promise.all 等待所有都完成(或第一个失败)。
	setTimeout(() => {
		console.log(i);
	}, 1000)
})

promise

es6 中的 promise 是可以解决异步问题的,而并不是promise本身是异步的。

let func = new Promise((resolve, reject) => {
	// 异步操作
})

resolve: 异步操作后执行成功的回调函数。

reject: 异步操作后执行失败的回调函数。
reject用法:

// 多次执行如下代码能得到 resolved 4 或者 数字 >= 5
let func = new Promise((resolve, reject) => {
	// 异步操作
	setTimeout(() => {
		var num = Math.ceil(Math.random() * 10);
		if (num < 5) {
			resolve(num);
		} else {
			reject('数字 >= 5')
		}
	}, 1000);
});

func.then((data) => {
	console.log('resolved', data);
}, (err) => {
	console.log('reject', err);
})

then 中传了两个参数,then 方法可以接收两个参数。第一个对应 resolve 的回调,第二个对应 reject 的回调。所以我们能够分别拿到他们传过来的数据。

then 的链式用法
能简化层层回调,用维护转态、传递转态的方式使得回调函数能够及时调用。

func.then(() => {
	...
}).then(() => {
	...
})

catch 的用法
catch 和 then 的第二个参数一样,是用来置顶reject 的回调。
catch 和 then 的第二个参数不同处:
如果执行第一个 then 参数时代码出错了,并不会卡死 js,而是会进入到这个 catch 的方法中。

func.then(() => {
	// resolved
}).catch(() => {
	// rejected
})

all 的用法

let Promise1 = new Promise(function(resolve, reject){})
let Promise2 = new Promise(function(resolve, reject){})
let Promise3 = new Promise(function(resolve, reject){})

let p = Promise.all([Promise1, Promise2, Promise3])

p.then(funciton(){
  // 三个都成功则成功  
}, function(){
  // 只要有失败,则失败 
})

all 可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。

race 的用法
race 函数返回一个 Promise,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。

var p1 = new Promise(function(resolve, reject) {
    setTimeout(reject, 10, "one");
});
var p2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 20, "two");
});
var p3 = new Promise(function(resolve, reject) {
    setTimeout(reject, 30, "three");
});


Promise.race([p1, p2,p3]).then(function(value) {
  // 未被调用
    console.log(value, 11111)
}, function(reason) {
  console.log(reason); // "one"
  // p1 更快,所以它失败了
});

捕获错误的方法 catch()
解析全部方法 all()
竞赛 race()
生成一个成功的promise resolve()
生成一个失败的promise reject()

try catch 语法:

try {
    tryCode - 尝试执行代码块
}
catch(err) {
    catchCode - 捕获错误的代码块
}
finally {
    finallyCode - 无论 try / catch 结果如何都会执行的代码块
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值