javascript中Promise深入理解
因为js是单线程的脚本语言,所以在执行代码时会先执行主程序中的代码,如果需要加载的程序,会先加载,待其加载完成后,将其丢到主程序中执行。
下面是一个简单的异步操作:
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div{
width: 200px;
height: 200px;
background: green;
position: absolute;
left:0px;
}
</style>
</head>
<body>
<div></div>
<script>
function interval(callback,time){
let id = setInterval(()=>{
callback(id)
},time)
}
interval((idC)=>{
let div = document.querySelector("div");
let left = parseInt(window.getComputedStyle(div).left);
div.style.left = left+ 10+"px";
if(left >=200){
clearInterval(idC);
}
},100)
console.log("2021");
// 注意:在js的定时器中,定时器返回的值是定时器的编号。
// 因为js是单线程的语言,所以在js中只会执行主程序,不断轮询主程序
</script>
</body>
</html>
这里设置定时器,因为定时器需要等待,所以当该程序运行时,会将定时器模块丢到定时器模块加载,此时主程序会将主程序中的文件先执行,待定时器模块加载完毕后,会将其丢到主程序中等待执行。此时主程序会不断地进行轮询操作。
下面是图片加载操作:
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function imageLoad(src, resolve, reject) {
let image = new Image();
image.src = src;
image.onload = resolve(image);
image.onerror = reject;
}
setTimeout(() => {
imageLoad('./img_1.jpg', function () {
document.body.appendChild(arguments[0]);
console.log("图片加载成功");
}, () => {
console.log("图片加载失败");
})
}, 1)
console.log("图片加载的小demo");
// 这里是异步处理,首先图片加载需要耗时,所以会在另一个内存空间内进行处理,当处理完成后,处理的结果会返回主程序
// 此时javascript会优先处理主程序中的程序,并且会不断的轮询其他完成了的程序
</script>
</body>
</html>
解析:这里是异步处理,首先图片加载需要耗时,所以会在另一个内存空间内进行处理,当处理完成后,处理的结果会返回主程序。此时javascript会优先处理主程序中的程序,并且会不断的轮询其他完成了的程序。
Promise简介:
<script>
new Promise((resolve,reject)=>{
resolve("解决")
}).then((value)=>{
console.log("成功1");
},()=>{
console.log("失败1");
}).then((value)=>{
console.log("成功2");
},()=>{
console.log("失败2");
})
console.log("这里是主程序");
</script>
解析:这里是Promise对象设置一个异步操作,传入两个参数表示状态,只有当状态改变的时候才能执行下面的then操作,不设置状态表现是pending状态。当设置状态是resolve时表示状态解决,当设置reject时表示失败状态。同时then中传入的两个参数是两个处理函数,分别是对成功和失败的情况下进行处理的操作。
②上面代码中的最后一个是主程序,上面的Promise是微程序,我们上面的代码中的图片加载以及定时器操作都是宏程序。主程序的处理次序要优先于微程序,微程序的处理次序要优先于宏程序。
各类程序的优先次序
<script>
setTimeout(function(){
console.log("setTimeOut");
},0);
new Promise((resolve,reject)=>{
resolve();
console.log("Promise");
}).then(()=>{
console.log("成功");
})
console.log("主程序");
// 上面几个顺序是:
// Promise
// 主程序
// 成功
// setTimeout
</script>
解析:上面程序中的定时器会先放到宏任务中进行加载,Promise中的console.log(“Promise”);会放到主程序中进行加载,然后通过状态改变开启一个微任务,由于主程序中的操作优先于微程序中的任务,优先于宏任务中的任务。所以上面便是最终的结果。
<script>
new Promise((resolve)=>{
console.log("哈哈哈哈");
setTimeout(function(){
resolve();
console.log("setTimeOut");
},0)
}).then(()=>{
console.log("成功");
})
console.log("主程序");
// 打印的结果是
// 哈哈哈哈
// 主程序
// setTimeout
// 成功
</script>
解析:在promise中刚开始的哈哈哈哈语句是放到主程序中执行。并且其中存放了一个setTimeOut,所以会放到宏任务中。在宏任务中的内容开始到主程序执行的时候,此时setTimeOut语句就会在主程序中执行,但是resolve()这样一个微任务程序,会在微任务序列中等待执行,所以最后执行成功。
<script>
let p1 = new Promise((resolve,reject)=>{
// resolve("成功aaaa");
reject("失败")
});
console.log(p1);
let p2 = new Promise((resolve,reject)=>{
resolve(p1);
}).then((msg)=>{
console.log(msg);
},()=>{
console.log('失败');
});
</script>
解析:当一个Promise对象作为一个参数传入下一个Promise对象中.如果传入的promise对象为失败状态,则下一个Promise也是失败状态。第二:promise()对象状态一旦确定,就不可以更改
Promise中的then
<script>
<script>
new Promise((resolve,reject)=>{
resolve("成功了");
// reject("失败了")
}).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
})
// 解析:只有当resolve或者reject执行的时候,才能将程序放置到微任务程序中
// 如果仅仅想要讨论一种状态,另外一种状态可以省略,必要时可以使用null。
</script>
</script>
解析:只有当resolve或者reject执行的时候,才能将程序放置到微任务程序中。如果仅仅想要讨论一种状态,另外一种状态可以省略,必要时可以使用null。
then的状态
<script>
<script>
let p1 = new Promise((resolve, reject) => {
// resolve("成功");
reject("失败1");
})
let p2 = p1.then((value) => {
console.log("成功2");
}, (reason) => {
console.log("失败2");
}).then((value)=>{
console.log("成功3");
},(reason)=>{
console.log("");
})
//失败2
//成功3
</script>
这里打印的结果是失败2,成功3,p1的then接收的一个reject的结果,但是第二的then当没有设置状态改变的时候,默认的状态是成功的状态。
对then返回的处理
<script>
//一、这里的then直接打印出结果
new Promise((resolve,reject)=>{
resolve("成功了");
}).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
})
//二、then默认是成功状态
new Promise((resolve,reject)=>{
resolve("成功了");
}).then(value=>{
return "我是dl"
},reason=>{
console.log(reason);
}).then(value=>{
console.log(value);
})
//三、一个Promise对象对应一个then函数 当Promise处于pedding状态,下面的then就会进行等待
new Promise((resolve, reject) => {
resolve("成功了")
}).then(value => {
return new Promise((resolve, reject) => {
// resolve("我是dl");
reject("失败了不是")
})
}, reason => {
console.log(reason);
}).then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
//四、 当设置定时器的时候,后面的then必须设置到等到状态才可以执行
new Promise((resolve, reject) => {
resolve("成功了")
}).then(value => {
return new Promise((resolve, reject) => {
// resolve("我是dl");
setTimeout(function () {
reject("失败了不是")
}, 3000)
})
}, reason => {
console.log(reason);
}).then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
//五、 一个Promse对应着一个then,后面的then(),就是对Promise的处理
new Promise((resolve, reject) => {
resolve("成功了")
}).then(value => {
return new Promise((resolve, reject) => {
reject("失败了不是")
}).then(null, r => {
return new Promise((resolve, reject) => {
resolve("hhhhhh")
})
});
}, reason => {
console.log(reason);
}).then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
</script>
其他类型的Promise封装
<script>
//一、正常的使用Promise对象
new Promise((resolve,reject)=>{
resolve("成功了");
}).then(value=>{
return new Promise((resolve,reject)=>{
resolve("成功哈哈哈")
})
},reason=>{
console.log(reason);
}).then(value=>{
console.log(value);
})
//二、使用对象字面量来封装
new Promise((resolve,reject)=>{
resolve("成功");
}).then(value=>{
return { //这里使用return返回一个Promise对象
then(resolve,reject){
resolve("哈哈哈")
}
}
},reason=>{
console.log(reason);
}).then(value=>{
console.log(value);
})
//三、使用对象字面量来封装
new Promise((resolve,reject)=>{
resolve("成了")
}).then(value=>{
class dh{
then(resolve,reject){
reject("拒绝")
}
}
return new dh;
},reason=>{
console.log(reason);
}).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
})
//四、使用静态方法进行封装
new Promise((resolve,reject)=>{
resolve("成了");
}).then(value=>{
class hd{
static then(resolve,reject){
resolve("哈哈哈哈");
}
}
return hd;
},reason=>{
console.log(reason);
}).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
})
</script>
对ajax异步操作进行处理
<script>
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function ajax(url){
return new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
xhr.open("GET",url);
xhr.send();
xhr.onload = function(){
if(this.status == 200){
resolve(this.response);
}else{
reject("加载错误")
}
}
xhr.onerror = function(){
reject(this);
}
})
}
ajax('http://127.0.0.1:5000/user/dl').then(value=>{
// value = eval('(' + value + ')');
return ajax("http://127.0.0.1:5000/id/201902091").then(value=>{
console.log(value);
},reason=>{
console.log(reason);
});
console.log("http://127.0.0.1:5000/id/"+value['id']);
},reason=>{
console.log(reason);
})
</script>
</body>
</html>
</script>
这里的程序,只有等到上一级的操作完成后 ,才能进行下一次操作。
对Promise中失败的处理
<script>
//一、这里是直接通过使用reject进行错误返回
new Promise((resolve,reject)=>{
reject("失败")
}).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
})
//二、当一些语法错误之类的,js会直接返回reject对象.
new Promise((resolve, reject) => {
hs+10;
}).then(value => {
console.log(value);
}, reason => {
console.log(reason.message);
})
//三、可以自己去抛出错误,这样也会返回reject
new Promise((resolve, reject) => {
throw new Error("shibai")
}).then(value => {
console.log(value);
}, reason => {
console.log(reason.message);
})
//四、
new Promise((resolve, reject) => {
try{
hs+10;
}catch{
console.log("这里出现错误");
}
}).then(value => {
console.log(value);
}, reason => {
console.log(reason);
})
//五、
new Promise((resolve,reject)=>{
reject("失败")
}).then(value=>{
return new Promise((resolve,reject)=>{
resolve("chengg")
})
},reason=>{
console.log(reason);
}).catch(error=>{
console.log(error);
})
//catch可以解决reject出现的错误,可以解决前面所有出现的错误,但是不能解决.其后面出现的错误,如果是前面出现错误被自身的reject()回调函数解决,则后面则不接收错误
</script>