本文已参与「新人创作礼」活动,一同敞开创作之路。
知道Promise目标的你,知道在运用Promise目标的时候,咱们怎么做到在运用中如虎添翼嘛?10分钟带你迅速上手!
一、Promise的诞生
1、回调阴间
开始javascript的异步完成便是运用回调函数。回调阴间便是:一个函数需求等它的回调函数(或许回调和回调的回调…)履行完毕之后再履行。简略来说,回调函数里边嵌套回调函数
。而由于回调阴间的问题,Promise就出现了。咱们看看什么是回调阴间:
// 回调阴间
//阴间回调
setTimeout(function () { //第一层
console.log(1);//等4秒打印1,然后履行下一个回调函数
setTimeout(function () { //第二层
console.log(2);//等3秒打印2,然后履行下一个回调函数
setTimeout(function () { //第三层
console.log(3);//等2秒打印3,然后履行下一个回调函数
setTimeout(function () { //第四层
console.log(4);//等1秒打印4
}, 1000)
}, 2000)
}, 3000)
}, 4000)
可看出回调阴间的特点
:
1.难以复用
2.仓库信息被断开
3.凭借外层变量
回调阴间是为了让咱们代码履行顺序的一种操作(解决异步),可是它会使咱们的可读性十分差。当你有100个,1000个…,代码会不断右移,不行优雅,也会影响性能。嵌套和缩进仅仅回调阴间的一个梗罢了,它导致的问题远非嵌套导致的可读性下降罢了。接下里咱们今天的意图,便是将上面的回调阴间用Promise解决。
二、Promise的行为
1、Promise的语法
Promise的根本语法
:Promise函数接收一个函数作为参数,这个函数有两个参数,一个是成功函数(resolve),一个是失利函数(reject)。Promise的.then接收两个回调函数,一个是成功函数的回调,一个是失利函数的回调。这两个函数可选,不一定要供给
//Promise语法
let myPromise = new Promise(function(resolve, reject) {
// "Producing Code"(或许需求一些时刻)
resolve(); // 成功时
reject(); // 犯错时
});
// "Consuming Code" (有必要等待一个实现的承诺)
myPromise.then(
function(value) { /* 成功时的代码 */ },
function(error) { /* 犯错时的代码 */ }
);
特别注意:
(1)Promise目标中的状况不会被外界干扰。状况的改动取决于异步的操作成果。
(2)Promise目标的状况一旦被改动,就不会进行再次改动。
例如:
let myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');//第一次状况为成功
reject('no');//不会改动
})
}).then(
function (result) { console.log('resolved'); },//成功状况履行then后边的成功回调函数
function (error) { console.log('reject'); }
)
//resolved
(3)Promise新建后就会当即履行,Promise后边的.then是一个异步操作,在事情循环中叫做“微使命”。会放在同步代码后边履行。
例如:
let myPromise=new Promise((resolve,reject)=>{
console.log('Promise');//1
resolve();
})
.then(()=>{//这儿是一个异步操作
console.log('succeed');//3
})
console.log('Promise resolved');//2
// Promise
// Promise resolved
// succeed
2、Promise的办法
(1)Promise.prototype.then()
then办法的回来成果是新的Promise实例
,目标状况由回调函数的履行成果决议。then办法后边还能够再调用另一个then办法,构成链条。选用链式的then
,能够指定一组依照次第调用
的回调函数。
const p = new Promise((resolve, reject) => {
setTimeout(() => {
//设置 p 目标的状况为失利,并设置失利的值
reject("犯错啦!");
}, 1000)
});
p.then(
function(value){},
function(reason){console.log(reason);}
)
.then(()=>{
console.log(123)
});
(2)Promise.prototype.catch()
catch()用于指定发生过错时的回调函数.例如:
const p = new Promise((resolve, reject) => {//p为Promise的实例
setTimeout(() => {
//设置 p 目标的状况为失利,并设置失利的值
reject("犯错啦!");//reject()办法的作用,等同于抛犯过错
}, 1000)
});
// p.then(function(value){},function(reason){
// // console.error(reason);
// console.log(reason);
// });
p.catch(function (reason) {//相当于上面的.then(...)
console.log(reason);//捕获reject状况的值
});
主张总是运用catch()
办法,而不运用then()
办法的第二个参数.
catch()还能够这样运用:
const myPromise = new Promise(function(resolve, reject) {
throw new Error('犯错啦');//从这抛犯过错,catch()指定的回调函数也能够捕获
});
promise.catch(function(error) {
console.log(error);
});
(3)Promise.prototype.finally()
finally()
办法用于指定不管 Promise 目标最终状况怎么,都会履行的操作。并且finally
办法总是会回来本来的值。举个比如:
function a(){
return new Promise((resolve,reject)=>{
resolve('ok')
},1000)
}
function b(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('no')
},1500)
})
}
function c(){
setTimeout(()=>{
console.log('finally');
},500)
}
a()
.then((res)=>{
console.log(res);
return b()
})
.catch((err)=>{
console.log(err);
})
.finally(c)//参数不是回调函数,假如是回调函数也不需求带参
//ok
//no
//finally //阐明finally()照样履行,有打印
(4)Promise.resolve()
将现有目标转为 Promise 目标,状况为resolved
。举例如下:
let myString='hello';
console.log(myString);//hello
const myPromise=Promise.resolve(myString)//带参
//等同于const myPromise=Promise.resolve('hello')
console.log(myPromise);//Promise { 'hello' }
myString=Promise.resolve();//不带参,直接调用
console.log(myString);//Promise { undefined }
myString.then(result=>{//阐明myString已经是Promise目标了,只有Promise目标才有.then
console.log(result);//undefined
})
(5)Promise.reject()
也会回来一个新的 Promise 实例,该实例的状况为rejected
。简略举例:
// 以上代码等于
const p=new Promise((resolve,reject)=>{
reject('error')
})
p.catch(error=>{
console.log(error);//error
})
// 或许
p.then(function(){},function(error){console.log(error);})//error
// 或许
p.then(null,function(error){console.log(error);})//error
// 或许
p.then(undefined,function(error){console.log(error);})//error
(6)Promise.all()
all()是将多个 Promise 实例,包装成一个新的 Promise 实例。接收一个数组作为参数,数组的每一项都是Promise目标的实例。假如不是,会通过Promise.resolve()将参数转为Promise实例,再进行处理。all()用于将多个 Promise 实例,包装成一个新的 Promise 实例
。
// promise.all()
const myPromise1=new Promise((resolve,reject)=>{
resolve('sure');
})
.then(result=>result)
const myPromise2=new Promise((resolve,reject)=>{
reject('cancel')
})
.then(result=>result)
.catch(error=>error)//myPromise2有自己的catch
//感兴趣的小伙伴能够尝试,假如删除myPromise2.catch(...)后Promise.all([myPromise1,myPromise2])会怎么?
Promise.all([myPromise1,myPromise2])//myPromise1,myPromise2都处于成功状况
.then(result=>{console.log(result);})//走这儿 [ 'sure', 'cancel' ]
.catch(error=>{console.log(error);})
(7)Promise.race()
race()是将多个 Promise 实例,包装成一个新的 Promise 实例。接收一个数组作为参数,数组的每一项都是Promise目标的实例。假如不是,会通过promise.resolve()将参数转为Promise实例,再进行处理。只要参数的Promise实例有一个首先改动状况,则状况改动
。例如:
const myPromise2 = new Promise((resolve, reject) => {
setTimeout(()=>{
reject('cancel')
},3000)
//假如将时刻改为<2000,Promise.race([myPromise1, myPromise2])走哪一步呢?
})
.then(result => result)
.catch(error => error)
const myPromise1 = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve('sure');
},2000)//myPromise1比myPromise2更先改动状况
})
.then(result => result)
Promise.race([myPromise1, myPromise2])
.then(result => { console.log(result); })//走这儿,sure
.catch(error => { console.log(error); })
简要说一下const p1=Promise.all([promise1,promise2,promise3]) 和const p2=Promise.race([promise1,promise2,promise3])的
区别
:–前者Promise的实例状况都为resolved时,p1调用.then()里边成功时的回调函数;假如实例状况有一个为rejected,p1调用.then()里边失利时的函数或许走.catch()
–后者注重时序,假如首先改动状况的实例为resolved,则p2为reslove状况;否则,为reject状况。
三、Promise的场景
1、Ajax请求
<head>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<div class="name">
<audio id="audio" controls></audio>
</div>
<script>
function getSong() {
return new Promise((resolve, reject) => {
$.ajax({
url: 'https://www.fastmock.site/mock/c024e8920dd6003c63dcd9ed2bbf6cb9/music/music',
dataType: 'json',
success(res) {
console.log(res);
url = res[0].url;
}
})
resolve();
})
}
function playSong() {
let audio = document.getElementById('audio');
window.addEventListener('click', function () {
audio.src = url;
audio.play()
})
}
getSong().then(playSong())
</script>
</body>
2、文件读取
// 引进fs模块
const fs=require('fs');
// 运用Promise封装
const P=new Promise(function(resolve,reject){
fs.readFile('./text/2.md',(err,data)=>{
// 假如地址过错,抛出反常
if(err) reject(err) ;
// 假如成功,输出内容
resolve(data);
});
});
P.then(function(value){
console.log(value.toString());
},function(reason){
console.log("defeat!!!!");
});
3、图片加载
<body>
<img src="http://m.imeitou.com/uploads/allimg/220514/5-220514101036.jpg" alt="景色" id="myImage">
<script>
const preloadImage = function (path) {
return new Promise(function (resolve, reject) {
const image = new Image();
// 图片加载成功
image.onload=()=>{
resolve(image)
}
// 图片加载失利
image.onerror=()=>{
reject('sorry,cannot loding picture')
};
image.src = path;
});
};
// 获取图片DOM节点
var preImage=document.getElementById('myImage')
// 图片预加载
preloadImage('https://www.6hu.cc/storage/2022/12/1670492847-af9a1be924976f9.jpg')
.then(targetImage=>
// 点击页面切换图片,让图片加载
window.onclick=function(){
setTimeout(()=>{
preImage.src=targetImage.src
},1000)
}
)
</script>
</body>
4、函数封装
//例如将微信小程序里的showModal进行Promise封装,那么在任何需求用到此函数的直接引进就很方便了
// promise形式 封装 showModal
export const showModal=({content})=>{
return new Promise((resolve,reject)=>{
wx.showModal({
title:'提示',
content:content,
success: (result) => {
resolve(result);
},
fail: (err) => {
reject(err);
}
});
})
}
四、Promise的短板
1.无法撤销Promise,一旦新建它就会当即履行,无法中途撤销
2.假如不设置回调函数,Promise内部抛出的过错,不会反映到外部
3.当处于pending状况时,无法得知现在发展到哪一个阶段,是刚刚开始仍是即将完成
总结
恭喜你看到文章结尾了,相信你能够写出Promise方案解决第一个回调阴间的异步问题了,快去试试把!