Promise是甚么?
认知
抽象化抒发
Promise是两门捷伊技术(ES6规范)Promise是JS中展开触发器程式设计的新软件系统
附注:旧的计划是纯粹采用反弹表达式具体内容抒发
从句法上而言:Promise是两个内部结构Promise第一类的状况发生改变
Promise的状况指的是示例第一类中的两个特性PromiseState,它的值有四个:
pending:未下定决心的resolve/fulfilled:获得成功rejected:失利Promise的状况发生改变多于上面的四种情形:
由pending转变成resolved由pending转变成rejected放出极度:假如现阶段为pending就会转变成rejected表明:多于这2种,且两个Promise第一类根本无法发生改变一场,不论转变成获得成功却是失利,单厢有两个结论统计数据,获得成功的结论统计数据通常称作value,失利的结论统计数据通常称作reason。
Promise第一类结论值特性
Promise示例第一类中除了两个特性PromiseResult,留存着第一类获得成功/失利的结论。要想发生改变它的值,多于透过给resolve()或是reject()方式传参,获得成功时,将相关联统计数据传至resolve()方式,失利时,将相关联的统计数据传至reject()方式,后能在then(value => {}, reason => {})方式中抽出,value相关联着resolve()转交的模块,reason相关联着reject()转交的模块。
Promise的基本上采用
市场需求:点选按键,1秒后表明与否中大奖(30%机率中大奖)。若中大奖,弹出:恭贺恭贺,礼品为10万RMB宾利代金券;若未中大奖弹出:奋力拼搏。
html网页,放个副标题和按键方可:
<h2>Promise 全唇兰</h2>
<button>点选抽奖</button>
不采用Promise的js代码:
<script>
// 生成随机数
function rand(m, n) {
return Math.ceil(Math.random() * (n – m + 1) + m – 1);
}
/** 市场需求:
* 点选按键, 2s 后表明是否中大奖(30%机率中大奖) * 若中大奖,弹出:恭贺恭贺,礼品为 10万 RMB 宾利代金券
* 若未中大奖弹出: 奋力拼搏
*/
// 旧的方式
const btn = document.querySelector(button);
// 绑定单击事件
btn.addEventListener(click, function () {
// 定时器
setTimeout(() => {
// 30% 中大奖机率,如果数字为1—100,那么我们随机数小于30,就认为它中大奖了(简易的算法) let n = rand(1, 100);
// 判断
if (n <= 30) {
alert(恭贺恭贺,礼品为 10万 RMB 宾利代金券);
} else {
alert(奋力拼搏);
}
}, 1000);
})
</script>
采用Promise,js代码:
<script>
// 生成随机数
function rand(m, n) {
return Math.ceil(Math.random() * (n – m + 1) + m – 1);
}
const btn = document.querySelector(button);
// 绑定单击事件
btn.addEventListener(click, function () {
// Promise 形式实现
// resovle 解决 是表达式类型的统计数据 触发器任务获得成功时调用
// reject 拒绝 是表达式类型的统计数据 触发器任务失利时调用 let p = new Promise((resolve, reject) => {
setTimeout(() => {
// 30% 中大奖机率,假如数字为1—100,那么我们随机数小于30,就认为它中大奖了 let n = rand(1, 100);
// 判断
if (n <= 30) {
resolve(); // 将 promise 第一类的状态设置为 获得成功 } else {
reject(); // 将 promise 第一类的状况设置为 失利
}
}, 1000);
});
// 调用 then 方式
// then方式的第两个反弹表达式,promise第一类状态为获得成功时调用,第二个反弹表达式,promise第一类状况为失利时调用 p.then(() => {
alert(恭贺恭贺,礼品为 10万 RMB 宾利代金券);
}, () => {
alert(奋力拼搏);
})
})
</script>
现在市场需求变更,在弹出提示时,同时告知本次抽到的数字。
不采用Promise的js代码:
<script>
// 生成随机数
function rand(m, n) {
return Math.ceil(Math.random() * (n – m + 1) + m – 1);
}
// 旧的方式
const btn = document.querySelector(button);
// 绑定单击事件
btn.addEventListener(click, function () {
// 定时器
setTimeout(() => {
// 30% 中大奖机率,假如数字为1—100,那么我们随机数小于30,就认为它中大奖了
// let n = rand(1, 100);
// 判断
if (n <= 30) {
alert(恭贺恭贺,礼品为 10万 RMB 宾利代金券,您的中大奖数字为: + n);
} else {
alert(奋力拼搏,您抽中的数字为: + n);
}
}, 1000);
})
</script>
采用Promise的js代码:
<script>
// 生成随机数
function rand(m, n) {
return Math.ceil(Math.random() * (n – m + 1) + m – 1);
}
const btn = document.querySelector(button);
// 绑定单击事件
btn.addEventListener(click, function () {
// 假如现在需要在弹出提示时,同时告知本次的号码,该怎么办?
// 只需要将获得成功或失利的值分别传至 resolve() 和 reject() 方式,然后再then()方式的两个反弹表达式中转交方可。 let p = new Promise((resolve, reject) => {
setTimeout(() => {
// 30% 中大奖机率,假如数字为1—100,那么我们随机数小于30,就认为它中大奖了 let n = rand(1, 100);
// 判断
if (n <= 30) {
resolve(n); // 将 promise 第一类的状况设置为 获得成功 } else {
reject(n); // 将 promise 第一类的状况设置为 失利
}
}, 1000);
});
// 调用 then 方式
// then方式的第两个反弹表达式,promise第一类状况为获得成功时调用,第二个反弹表达式,promise第一类状况为失利时调用 // value 值
// reason 理由
p.then((value) => {
alert(恭贺恭贺,礼品为 10万 RMB 宾利代金券,您的中大奖数字为: + value);
}, (reason) => {
alert(奋力拼搏, 您的号码为: + reason);
})
})
</script>
Promise的基本上流程
为甚么要采用Promise?
指定反弹表达式的方式更加灵活
旧的:必须在启动触发器任务前指定promise:启动触发器任务=> 返回promise第一类=>给promise第一类绑定反弹表达式(甚至能在触发器任务结束后指定两个或多个)支持链式调用,能解决反弹地狱问题
甚么是反弹地狱?
反弹表达式嵌套调用,外部反弹表达式触发器执行的结论是嵌套的反弹执行的条件
例如,上面的代码是Node.js的fs模块读取四个文件,并将读取到的结论展开拼接并且输出到控制台中。
fs.readFile(./resource/1.txt, (err, data1) => {
if (err) throw err;
fs.readFile(./resource/content.txt, (err, data2) => {
if (err) throw err;
fs.readFile(./resource/2.txt, (err, data3) => {
if (err) throw err;
console.log(data1 + data2 + data3);
})
})
})
这个代码片段,fs.readFile()在嵌套调用,这里就形成了反弹地狱。
反弹地狱的缺点
不便于阅读不便于极度处理软件系统?
采用promise链式调用,
终极软件系统:async/await
如何采用Promise?
API
Promise内部结构表达式
Promise的内部结构表达式:Promise(executor){}
executor表达式:执行器(resolve, reject) => {}resolve表达式:内部定义获得成功时我们调用的表达式reject表达式:内部定义失利时我们调用的表达式表明:executor会在Promise内部立即同步调用,触发器操作在执行器中执行。
Promise.prototype.then方式
Promise.prototype.then方式:(onResolved, onRejected) => {}
onResolved表达式:获得成功的回调表达式,通常这么写: value => {}onRejected表达式:失利的反弹表达式,通常这么写reason => {}表明:指定用于得到获得成功value的获得成功反弹和用于得到reason的失利反弹,返回两个捷伊Promise第一类。
Promise.prototype.catch方式
Promise.prototype.catch方式:(onRejected) => {}
onRejected表达式:失利的回调表达式,通常这么写reason => {}
catch()根本无法指定失利的反弹,不能指定获得成功的反弹。其实也是采用then()实现的.
表明:catch()是 then()的句法糖, 相当于: then(undefined, onRejected) 。
Promise.resolve方式
Promise.resolve方式:(value) => {}
value:获得成功的统计数据或Promise第一类
表明:返回两个获得成功/失利的Promise第一类
catch()方式和resolve()方式的采用:
<script>
// 假如传至的模块为 非Promise类型的第一类,返回的结论为 获得成功的Promise第一类
// 假如传至的参数为 Promise第一类,则模块的结论下定决心了resolve的结论 let p1 = Promise.resolve(555);
console.log(p1); // Promise {<fulfilled>: 555}
let p2 = Promise.resolve(new Promise((resolve, reject) => {
resolve(OK);
}));
console.log(p2); // Promise {<fulfilled>: “OK”}
// 传至失利的Promise
let p3 = Promise.resolve(new Promise((resolve, reject) => {
reject(Error);
}));
console.log(p3); // Promise {<rejected>: “Error”}
// 失利的同时还报错了,原因是没有对错误展开处理,这里采用catch()展开处理就能解决报错 p3.catch(reason => {
console.log(reason); // Error
})
</script>
Promise.reject方式
Promise.reject方式:(reason) => {}
reason:失利的原因
表明:返回两个失利的Promise第一类
reject()方式的示例:
<script>
// 总结,Promise.reject()方式,不论你传至甚么得到的都是失利的Promise第一类,并且失利的结论就是你传至的模块。 let p = Promise.reject(555);
console.log(p);
let p2 = Promise.reject(hello);
console.log(p2);
let p3 = Promise.reject(new Promise((resolve, reject) => {
resolve(OK);
}))
console.log(p3);
</script>
Promise.all方式
Promise.all方式:(promises) => {}
promises模块:包含n个Promise第一类的数组
表明:返回两个捷伊Promise第一类,多于所有的Promise都获得成功才获得成功,只要有两个失利了就直接失利,失利的结论就是失利的Promise第一类的结论。
all()方式的示例:
<script>
let p1 = new Promise((resolve, reject) => {
resolve(OK);
});
let p2 = Promise.resolve(Success);
let p3 = Promise.resolve(Oh Yeah);
let result1 = Promise.all([p1, p2, p3]);
console.log(result1); // 返回两个获得成功的Promise第一类,第一类的结论是两个数组,数组中存有四个获得成功的promise第一类的结论
// 假如数组中 p2 是两个失利的Promise,那么all()方式返回的是两个失利的Promise第一类,并且失利的结论是数组中失利的Promise第一类的结论。 p2 = Promise.reject(Error);
let result2 = Promise.all([p1, p2, p3]);
console.log(result2);
</script>
Promise.allSettled方式
Promise.allSettled方式:(promises) => {}
promises模块:包含n个Promise第一类的数组
表明:该方式返回的结论总是状况为获得成功的Promise第一类,这个Promise第一类的结论值是包含promises模块中每两个promise第一类的状况以及结论值的第一类数组。
注意和all()方式的区别。
allSettled()方式示例:
<script>
// 声明两个Promise第一类
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(商品统计数据 – 1);
// reject(ERROR)
}, 1000);
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(商品统计数据 – 2);
reject(出错了);
}, 1000);
})
// 调用allSettled() 方式 该方式返回的结论总是获得成功的Promise第一类, // 它的结论值是包含每两个promise第一类的状况以及结论值的第一类。
let result = Promise.allSettled([p1, p2]);
console.log(result);
let res = Promise.all([p1, p2]); // 全部获得成功,才会返回获得成功的Promise第一类
console.log(res);
</script>
Promise.race方式
Promise.race方式:(promises) => {}
promises模块:包含n个Promise第一类的数组
表明:返回两个捷伊Promise第一类,第两个完成的Promise第一类的结论状况就是最终的结论状况
race()方式的示例:
<script>
// 同步代码
let p1 = new Promise((resolve, reject) => {
resolve(OK);
})
let p2 = Promise.resolve(Success);
let p3 = Promise.resolve(Oh Yeah);
// 调用
let result1 = Promise.race([p1, p2, p3]);
// 代码从上往下执行,所以p1最先执行,所以result的状况和结论应该是p1的状况和结论。 console.log(result1);
// 触发器代码
let p4 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(OK);
}, 2000);
})
let p5 = Promise.reject(Error);
let p6 = Promise.resolve(Oh Yeah);
let result2 = Promise.race([p4, p5, p6]);
// p4为触发器代码,p5 会先于p4、p6执行,所以p5的状况和结论即为result2的状况和结论。
console.log(result2);
</script>
Promise的几个关键问题
如何发生改变Promise的状况?
发生改变Promisede状况有四种方式:
resolve(value):假如现阶段是pending就会改转变成resolved(fulfilled)reject(reason):假如现阶段是pending就会转变成rejected放出极度:假如现阶段是pending就会转变成rejected示例:
<script>
let p = new Promise((resolve, reject) => {
// 1. resolve表达式
// resolve(OK); // pending => fulfilled(resolved)
// 2. reject 表达式 // reject(Error); // pending => rejected
// 3. 放出错误
// throw 出问题了; // pending => rejected
})
console.log(p);
</script>
两个Promise指定多个获得成功/失利的反弹表达式,单厢调用吗?
指定反弹用的就是then(),所以这个题目的意思是假如采用then()方式为两个promise对象指定多个反弹,那么这些反弹与否单厢执行?
答案是:当Promise改转变成相关联状况时单厢调用。
示例:
<script>
let p = new Promise((resolve, reject) => {
resolve(OK);
})
// 指定反弹 – 1
p.then(value => {
console.log(value);
})
// 指定反弹 – 2
p.then(value => {
alert(value);
})
// 有弹框,控制台有输出,表明这两个反弹都执行了。 </script>
发生改变Promise状况和指定反弹表达式谁先执行谁后执行?
都有可能,正常情形下是先指定反弹再发生改变状况,但也能先发生改变状况再指定反弹如何先改状况再指定反弹?在执行器中直接调用resolve()/reject()then()方式延迟更长时间才被调用3. 甚么时候才能得到统计数据?
假如先指定的反弹,那当状况发生发生改变时,反弹表达式就会调用,得到统计数据假如先发生改变的状况,那当指定反弹时,反弹表达式就会调用,得到统计数据示例:
<script>
let p = new Promise((resolve, reject) => {
// setTimeout(() => { // 触发器任务 resolve(OK); // 同步任务
// }, 1000)
})
p.then(value => {
console.log(value);
}, reason => {
})
// 1. 当Promise内部结构表达式中的executor执行器表达式内部是同步任务时,先发生改变状况,在执行then()方式指定反弹(注意是指定反弹,不是执行反弹)
// 2. 当Promise内部结构表达式中的executor执行器表达式内部是触发器任务时,那么是先执行then()方式指定反弹表达式,再发生改变状况。 </script>
promise.then()返回新promise的结论状况由甚么下定决心?
简单抒发:由then()指定的反弹表达式执行的结果下定决心 详细抒发:假如放出极度, 新promise转变成rejected,reason为放出的极度 假如返回的是非promise的任意值,新promise转变成resolved,value为返回的值假如返回的是另两个新promise,此promise的结论就会成为新promise的结论示例:
<script>
let p = new Promise((resolve, reject) => {
resolve(OK);
// reject(error) })
// 执行 then 方式
let result = p.then(value => { // p 为获得成功的反弹
// console.log(value); // result的状况为fulfilled,结论为undefined,因为没有返回值
// 1. 放出错误
// throw 出了问题; // result 的状况为rejected,结论为出了问题
// 2. 返回结论为非 Promise 类型的第一类 // return 555; // result的状况为fulfilled,结论为555
// 3. 返回结论是Promise第一类
return new Promise((resolve, reject) => {
// resolve(success); // result的状况为fulfilled,结论为success
// reject(error); // result 的状况为rejected,结论为error
throw 出了问题; // result 的状况为rejected,结论为出了问题
})
}, reason => { // p 为失利的反弹
// console.log(reason); // result的状况为fulfilled,结论为undefined,因为没有返回值。 这里本身会输出error
// 1. 放出错误
// throw 出了问题; // result 的状况为rejected,结论为出了问题
// 2. 返回结论为非 Promise 类型的第一类
// return 555; // result的状况为fulfilled,结论为555
// 3. 返回结论是Promise第一类 return new Promise((resolve, reject) => {
// resolve(success); // result的状况为fulfilled,结论为success
// reject(error); // result 的状况为rejected,结论为error
// throw 出了问题; // result 的状况为rejected,结论为出了问题
})
})
console.log(result);
</script>
promise如何串连多个操作任务?
promise的then()返回两个捷伊promise,能继续调用then()方式,形成链式调用透过then的链式调用串连多个同步或触发器任务示例:
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(OK);
}, 1000);
})
p.then(value => {
return new Promise((resolve, reject) => {
resolve(success);
})
}).then(value => {
console.log(value) // success
}).then(value => {
console.log(value) // undefined
})
</script>
promise极度穿透?
当采用promise的then链式调用时,能在最后指定失利的反弹前面任何操作除了极度,单厢传到最后失利的反弹中处理 <script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(OK)
// reject(Err)
}, 1000);
})
p.then(value => {
// console.log(111);
throw 出问题了;
}).then(value => { // 也能在这里处理上面出现的错误
console.log(222)
}).then(value => {
console.log(333)
}).catch(reason => { // 这里采用catch,也能采用then console.warn(reason);
})
// 在调用链的最后指定失利的反弹,就能处理任务当中出现的错误,这个现象称作极度穿透。
</script>
如何中断promise链?
当采用promise的then链式调用时,想要在中间中断,不再调用后面的反弹表达式,有且多于两个办法:在反弹表达式中返回两个pending状况的promise第一类。
<script>
// 假如想要中断这个then调用链,有且多于两个方式,在需要中断的反弹表达式中,返回两个pending状况的promise第一类 let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(OK);
}, 1000);
})
p.then(value => {
console.log(111);
// 假如后面不想让它调用了,有且仅有两个方式:返回两个pending状况的promise第一类 return new Promise(() => {});
}).then(value => {
console.log(222)
}).then(value => {
console.log(333)
}).catch(reason => {
console.warn(reason);
})
</script>