Promise 是异步编程的一种解决方案。ES6将其写进了语言标准,统一了用法,并原生提供了Promise对象。
Promise 出现的原因
??在 Promise 出现以前,我们处理一个异步网络请求,大概是这样:
请求1(function(请求结果1){
请求2(function(请求结果2){
请求3(function(请求结果3){
请求4(function(请求结果4){
请求5(function(请求结果5){
请求6(function(请求结果3){
...
})
})
})
})
})
})
回调地狱现身了,我们基本上还要对每次请求的结果进行一些处理,代码会更加臃肿,在一个团队中,代码 review 以及后续的维护将会是一个很痛苦的过程。
有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
let 请求结果1 = 请求1();
let 请求结果2 = 请求2(请求结果1);
let 请求结果3 = 请求3(请求结果2);
let 请求结果4 = 请求2(请求结果3);
let 请求结果5 = 请求3(请求结果4);
特点
- 对象的状态不受外界影响 (3种状态)
- Pending状态(进行中)
- Fulfilled状态(已成功)
- Rejected状态(已失败)
- 一旦状态改变就不会再变 (两种状态改变:成功或失败)
- Pending -> Fulfilled
- Pending -> Rejected
执行顺序
以下表明,在Promise新建后会立即执行,所以首先输出 Promise对象内的内容 。然后,then方法指定的回调函数将在当前脚本所有同步任务执行完后才会执行.
PS:then()方法是异步执行。
let promise = new Promise(function(resolve,reject){
setTimeout(()=>{
console.log('在Promise新建后会立即执行');
resolve();
},5000);
})
promise.then(() =>{
console.log("then方法指定的回调函数将在当前脚本所有同步任务执行完后才会执行");
})
与定时器混用
let promise = new Promise(function(resolve, reject){
console.log("1");
resolve();
});
setTimeout(()=>console.log("2"), 0);
promise.then(() => console.log("3"));
console.log("4");
可以看到,结果输出顺序总是:1 -> 4 -> 3 -> 2 。1与4的顺序不必再说,而2与3先输出Promise的then,而后输出定时器任务。原因则是Promise属于JavaScript引擎内部任务,而setTimeout则是浏览器API,而引擎内部任务优先级高于浏览器API任务。
PS我通常都是用定时器解决同步加载数据未取到的现象。
拓展 async/await
async
??顾名思义,异步。async函数对 Generator 函数的改进,async 函数必定返回 Promise,我们把所有返回 Promise 的函数都可以认为是异步函数。特点体现在以下四点:
- 内置执行器
- 更好的语义
- 更广的适用性
- 返回值是 Promise
await
????????顾名思义,等待。正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值。另一种情况是,await命令后面是一个thenable对象(即定义then方法的对象),那么await会将其等同于 Promise 对象。
function sleep(ms) {
return new Promise(function(resolve, reject) {
setTimeout(resolve,ms);
})
}
async function handle(){
console.log("AAA")
await sleep(5000)
console.log("BBB")
}
handle();
// AAA
// BBB (5000ms后)
我们定义函数sleep,返回一个Promise。然后在handle函数前加上async关键词,这样就定义了一个async函数。在该函数中,利用await来等待一个Promise。
|