什么是异步呢,很好理解,一般的我们的代码执行的顺序是同步的,也就是执行完这条代码再执行下一条代码,而异步就是我们在某个时间点执行某个代码,而不是顺序执行
创建一条我们比较熟的预加载,这里就是一个典型的异步操作
var set=new Set();
for(var i=2;i<5;i++){
var img=new Image();
img.src="./img/"+i+"-.jpg";
img.addEventListener("load",loadHandler);
}
function loadHandler(e){
set.add(this);
if(set.size===3){
console.log("全部加载完成")
}
}
还有一些比较常见的封装好的函数,也是异步擦欧洲哦
setTimeout();
setInterval();
requestAnimationFrame();
console.log("a");
for(var j=0;j<1000000000;j++){
}
console.log("b");
一般程序员的思维就是不产生异步代码,让代码按顺序执行下去,于是就会出现在一个函数中不断回调我们所需要的代码,这样就会产生回调地狱,回调地狱会让代码一直往下沉,永远跳不除这个地狱中。
典型的回调地狱,因为我想让图片1加载完再加载图片2,然后图片3,4,5,所以就会不断回调onload事件,这样就会越陷越深,(用函数式编程就会完美地解决这个问题。)
var img=new Image();
img.src="./img/2-.jpg";
img.onload=function(){
var img1=new Image();
img1.src="./img/3-.jpg";
img1.onload=function(){
var img2=new Image();
img2.src="./img/4-.jpg";
img2.onload=function(){
console.log("a");
}
}
}
promise的出现完美地解决了这个问题,我们即使不用函数式编程也可以让代码异步执行,而不是顺序执行
Promise语法
var p= new Promise(function(resolve,reject){
resolve();
})
p.then(function(){
console.log("aaa");
})
var p= new Promise(function(resolve,reject){
reject();
});
p.catch(function(){
console.log("bbb");
})
promise分别有两个参数resolve,reject
这两个参数又分别可以传入一个参数。(仅一个参数)
当执行reject时,会执行后面的then当中第二个函数,如果有catch()
则会执行catch方法中的函
如果既有then中第二个函数也有catch,则完成then中第二个函数,catch不执行
注意!这两个参数只能选一个执行。
注意!!!
var p= new Promise(function(resolve,reject){
reject();
resolve();
console.log("ccc");
// 这两个方法只能二选其一执行
});
p.then(function(){
console.log("aaa");
}).catch(function(){
console.log("bbb");
})
console.log(p);
第二种写法,静态写法
这种写法跟上面的构建函数的写法完全相同,执行的功能也完全相同。
Promise.resolve().then(function(){
})
链式结构
在promise的写法中,then是可以连着写的,也就是我创建的then或者catch可以进行下一层
链式结构
loadImage("./img/2-.jpg").then(function(){
console.log("加载完成2-jpg");
return loadImage("./img/3-.jpg");
}).then(function(){
console.log("加载完成3-jpg");
return loadImage("./img/4-.jpg");
}).then(function(){
console.log("加载完成4-jpg");
});
promise的状态
PromiseState=pending 初始值
当执行resolve函数时或者reject函数时,首先判断PromiseState是不是pending,
如果是pending, 则运行掉用then中函数或者catch的函数
如果不是pending,就不执行后面的函数
如果执行resolve后就会被标记为fulfilled
如果执行reject后就会被标记为rejected
fulfilled resolve执行状态
rejected reject执行状态
pending 起始状态,挂起状态
promise的不同的三种状态,可以对应不同 的方法
小练习:用promise完成一个简单的红绿灯案例
function showLight(light,time){
if(!time) time=2000;
return new Promise(function(resolve,reject){
setTimeout(function(){
console.log(light)
resolve();
},time);
})
}
fns();
function fns(){
showLight("红灯").then(function(){
return showLight("黄灯");
}).then(function(){
return showLight("绿灯");
}).then(function(){
fns();
})
}
async 和await
async 返回一个Promise对象
await 后面只能等待promise对象resolve或者reject,其他都不行
await必须写在async函数中
async中的return 等同这个Promise的resolve
async中throw等同于这个Promise的reject
但是不管是return或者throw都不可异步返回,只有在使用await后才可以异步返回
async function fns(){
return 1;//使用return 相当于执行了resolve
throw "aaa";//使用 throw相对于执行了reject
一个小案例就能更好的理解这两个类promise
这里我需要按照a两秒后执行b,三秒后执行c,所以需要用到await
async function fns(){
console.log("a");
await waitTime(2000);//阻塞式同步
console.log("b");
await waitTime(3000);
console.log("c");
}
function waitTime(time){
return new Promise(function(resovle){
setTimeout(function(){
console.log(time/1000+"秒执行完成");
resovle();
},time);
})
}
同步任务 和 异步任务
这里的任务指的就是事件
异步任务分为两种:微任务和宏任务
宏任务 setTimeout setInterval
微任务 Promise
先执行同步任务,遇到微任务时,将其放在当前任务列的最底端,
遇到宏任务则会开辟一个新任务列,并且放在任务列的最顶端
这里我们需要清楚任务的执行顺序和创建顺序,先缕清执行顺序,然后在理解创建顺序,这里经常出现面试题