Promise
promise介绍
Promise
是ES6异步编程的解决方案,构造函数;
异步编程包括:fs文件操作、数据库操作、AJAX、定时器
优势:
- 支持链式调用,解决回调地狱;
//e.g.回调地狱,不便于阅读和异常处理
asyFunc1(opt,(...args1)=>{
asyFunc2(opt,(...args2)=>{
asyFunc1(opt,(...args3)=>{
asyFunc1(opt,(...args4)=>{
//some opertation
});
});
});
})
- promise指定回调的方式更为灵活:启动异步任务=>返回promise对象=>给promise对象绑定回调函数。
状态: PromiseState
实例对象的属性:
- pending 等待中,未得到结果
- resolved/ fullfilled 成功
- rejected 失败
变换方式:pending—>resolved 或者 pending—>rejected;
状态只能改变一次,不可逆。成功的结果称为value,失败称为reason。
new Promise(function(resolve, reject) {
if(true) { resolve() };
if(false) { reject() };
});
其中,resolve
和reject
都是函数,他们的作用是分别将状态修改成resolved
和rejected
。
此外,还可以通过throw""
来改变状态为rejected,抛出异常。
对象的值: PromiseResult
存储异步任务成功或者失败的结果
- resolve
- reject
API
- Promise构造函数:
Promise(excutor){}
,excutor
会在Promise内部立刻同步调用,异步在执行器中执行。
new Promise((resolve, reject) => {
resolve(4);
setTimeout(() => {
console.log(1);
}, 1000);
console.log(2);
}).then((value) => {
console.log(value);
});
console.log(3);
//结果为2,3,4,1
Promise.prototype.then
方法:(onResolved, onRejected)=>{}
Promise.prototype.catch
方法:(onRejected)=>{}
用来指定失败的回调。
new Promise((resolve, reject) => {
reject("err");
}).catch(reason => {
console.log(reason)
});
//结果为err
Promise.resolve
方法:(value) => {}
,返回一个成功或者失败的promise对象;如果传入的参数是非promise类型的对象,返回成功的promise对象;如果传入promise对象,则参数的对象决定了其结果。
let p1 = Promise.resolve(123);
console.log(p1);
let p2 = Promise.resolve(new Promise((resolve, reject) => {
resolve("ok");
}));
console.log(p2);
Promise.reject
方法:(reason) => {}
,无论传入类型为什么,返回失败的对象。
let p1 = Promise.reject(123);
console.log(p1);
Promise.all()
方法:返回一个新的promise,只有所有的promise都成功才成功,只要一个失败了就直接失败。Promise.race()
方法:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态。- 如果为一个promise对象指定多个成功或失败的回调函数(
.then
)。如果状态改变,那么对应的回调就都会执行;反之,如果是pending状态,就都不会执行。
案例
需求:点击按钮,2s后显示是否中奖(30%概率中奖),若中奖弹出,“恭喜中奖”;否则,“再接再厉”。
原来:
<body>
<div>
<button id="btn">
點擊中獎
</button>
</div>
<script>
function rand(m, n) {
return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
}
const btn = document.querySelector('#btn');
btn.addEventListener('click', function () {
setTimeout(() => {
let n = rand(1, 100);
// let n = 50;
if (n <= 30) {
alert("恭喜中奖");
}
else {
alert("再接再厲");
}
}, 1000);
})
</script>
</body>
这里解释一下HTML的DOM querySelector()
方法document.querySelector("#btn")
返回匹配指定选择器的第一个元素,此处获取文档中id是btn的对象元素。
改用promise:
包裹异步操作,then
处理成功和失败的结果。
btn.addEventListener('click', function () {
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1, 100);
// let n = 80;
if (n <= 30) {
resolve();
}
else {
reject();
}
}, 1000);
}).then(() => {
alert("恭喜中奖");
}, () => {
alert("再接再厲");
})
})
改进呈现随机得到的数字n:
btn.addEventListener('click', function () {
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1, 100);
// let n = 80;
if (n <= 30) {
resolve(n);
}
else {
reject(n);
}
}, 1000);
}).then((value) => {
alert("恭喜中奖,数字为:" + value);
}, (reason) => {
alert("再接再厲,数字为:" + reason);
})
});
util.promisify
采用遵循常见的错误优先的回调风格的函数(也就是将
(err, value) => ...
回调作为最后一个参数),并返回一个返回 promise 的版本。
const util = require('util');
const fs = require('fs');
const stat = util.promisify(fs.stat);
stat('.').then((stats) => {
// 使用 `stats` 做些事情
}).catch((error) => {
// 处理错误。
});
问:
- 改变promise状态和指定回调函数谁先谁后?【指定不是执行】
都有可能;在执行器中直接调用resolve()
或者reject()
实现改变状态再指定回调;如果执行器延长更长时间,例如,setTimeout(()=>{resolve("444");},1000);
时先调用then
。 .then
返回的结果由什么决定。如下:
let p = new Promise((resolve, reject) => {
resolve("ok");
});
let result = p.then(value => {
// 1.抛出错误,返回rejected
// throw "err";
// 2.返回非promise对象,返回状态成功,且结果为输入
// return 123;
// 返回promise对象,结果和状态示其返回结果而定
return new Promise((resolve, reject) => {
reject("123");
})
}, reason => {
console.warn(reason);
});
console.log(result);
- 串联多个任务
let p = new Promise((resolve, reject) => {
resolve("ok");
});
p.then(value => {
return new Promise((resolve, reject) => {
resolve("success")
})
}, reason => {
console.warn(reason);
}).then(value => {
console.log(value)
}).then(value => {
console.log(value)
});
//结果为success和undefined,因为没有前一个返回没有调用resolve,前一个返回一个成功的promise,结果是undefined。
- 异常穿透:在最后加
.catch
实现对上述串联任务的错误处理。 - 中断promise链:返回一个pending状态的promise对象。