在JavaScript的世界中,所有代码都是单线程执行的。
由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现:
function callback(){
console.log('5秒到了');
}
console.log("启动延时器");
setTimeout(callback, 5000);//5秒之后调用callback函数
console.log("启动延时器结束");
观察上述代码执行,在Chrome的控制台输出可以看到:
启动延时器
启动延时器结束
(等待5秒后)
5秒到了
可见,异步操作会在将来的某个时间点触发一个函数调用。
实例:回调地狱
启动一个4秒的延时器
4秒延时器结束以后,再去启动一个3秒的延时器
3秒的延时器结束以后,再去启动一个5秒的延时器
console.time("test1");
console.log("启动一个4秒的延时器");
setTimeout(function(){
console.log("4秒的延时器到了");
console.log("启动一个3秒的延时器");
setTimeout(function(){
console.log("3秒的延时器到了");
console.log("启动一个5秒的延时器");
setTimeout(function(){
console.log("5秒的延时器到了");
console.timeEnd("test1");
},5000)
},3000)
},4000)
对于程序执行的状态描述:
描述单个程序执行状态:同步和异步
同步:阻塞,当前程序要去执行,必须等前面的程序执行完毕以后才能执行。
异步:非阻塞,前面的程序是否执行完毕,根本就不影响当前程序是否执行。
描述多个程序之间的执行关系:并行和串行
串行:多个程序之间必须,按照顺序,A执行完毕以后,再去执行B,然后再去执行C。
并行:多个程序之间可以,同时进行。
同步并行
异步串行
异步并行
Promise语法(ECMA6/ECMA2015)
promise是解决回调地狱的方案之一
我们使用 Promise 的语法来解决回调地狱的问题
使代码拥有可读写和可维护性
实例:
var state = 0; //1 成功
new Promise(function(resolve, reject){
console.log("开始执行")
if(state == 1){
resolve("成功");
}else{
reject("失败");
}
}).then(function(msg){
console.log("then:" + msg);
}).catch(function(msg){
console.log("catch" + msg);
})
resolve 回调函数,是在程序运行成功以后调用的函数
resolve其实本质上是.then传入的函数
reject 回调函数,是在程序运行失败以后调用的函数
reject其实本质上是.catch传入的函数
new Promise() 创建了一个promise对象
promise对象后面只能跟一个.then方法和一个.catch方法。
【注】上面这个写法只能保证两个异步程序串行。
【注】如果我们要考虑两个以上的异步程序串行。
【注】为了异步程序串行所实现的。
实例:
1、启动一个4秒延时器
2、4秒到了以后,再去执行启动3秒的延时器
3、3秒到了以后,再去执行启动5秒的延时
var state = 1;//模拟代码是否执行成功
console.time("test2");
new Promise(function(resolve,reject){
console.log("启动4秒的延时器");
setTimeout(function(){
if(state == 1){
resolve("4秒到了成功");
}else{
reject("4秒到了失败");
}
},4000);
})
.then(function(msg){
console.log("then1," + msg);
return new Promise(function(resolve,reject){
console.log("启动3秒的延时器");
setTimeout(function(){
if(state == 1){
resolve("3秒到了成功");
}else{
reject("3秒到了失败");
}
},3000);
})
})
.then(function(msg){
console.log("then2," + msg);
return new Promise(function(resolve,reject){
console.log("启动5秒的延时器");
setTimeout(function(){
if(state == 1){
resolve("5秒到了成功");
}else{
reject("5秒到了失败");
}
},5000);
})
})
.then(function(msg){
console.log("then3," + msg);
console.timeEnd("test2");
})
.catch(function(msg){
console.log("catch," + msg);
})
扩展:
ECMA6的 Promise语法,编写的代码的时候,
虽然说解决,回调地狱和结构的问题,写起来代码特别的臃肿,写起来比较麻烦。
ECMA7(2016年)是回调地狱的终极解决方案。
新增语法:
async、await (async wait)
我们可以用 async / await 语法把 异步代码写的看起来像同步代码
async function goHome() {
let result = await new Promise(function () { … })
// 这里的代码会在上面的 promise 结束以后在执行
console.log(result)
}
异步执行的函数:
function show(){
return new Promise(function(resolve,reject){
resolve("hello world");
})
}
var res = show();
alert(res);//object Promise
res.then(function(msg){
alert(msg);//hello world
})
异步函数的声明:
async function go(){
var res = show();
alert(res);//[object Promise]
res.then(function(msg){
alert(msg);//hello world
})
var res = await show();
alert(res);
}
go();
定外卖实例:
异步程序串行
console.log("1.点了一个外卖");
new Promise(function(resolve){
console.log("外卖小哥送外卖中...");
setTimeout(function(){
console.log("3、外卖到了");
console.log("4、吃上了外卖");
resolve("2、回到直播间讲课");
},5000);
}).then(function(msg){
console.log(msg);
})
async function go(){
var res = await new Promise(function(resolve){
console.log("外卖小哥送外卖中...");
setTimeout(function(){
//异步并行
console.log("3、外卖到了");
console.log("4、吃上了外卖");
console.log("2、回到直播间讲课");
},5000);
})
//异步程序串行
console.log(res);
}
go();
await 异步程序持续多长时间,都会等异步程序执行完毕以后再接着往下执行
await 异步程序串行的操作,如果当前的代码执行没有完毕,必定会,阻塞。
async function go(){
console.time("test2");
var res1 = await takeLongTime(4000);
console.log("程序1,then1," + res1);
var res2 = await takeLongTime(4000);
console.log("程序2,then2," + res2);
var res3 = await takeLongTime(4000);
console.log("程序3,then3," + res3);
console.timeEnd("test2");
}
go();