Promise
1.Promise是什么?
1.Promise是异步编程的一种解决方案
2.那么什么时候我们会处理异步事件呢?
-一种常见的应用场景是网络请求
-我们封装一个网络请求函数是因为不能立即拿到结果,所以我们往往需要传入另外一个函数,在数据请求成功时,将数据通过传入的函数调回去
-如果是一个简单的网络请求,那么这种方案不会带来太大的麻烦但是当网络请求非常复杂时就会出现回调地
3.我们来考虑这样一个问题:我们需要通过url1从服务器加载data1,data1中包含下一个请求的url2,我们通过url2从服务器加载data2,data2中包含url3,我们通过url3最终拿到data3,返回数据
通过对上述案例的分析,我们可以看到,虽然可以得到数据但是这样的代码写出来不仅难看而且难以维护,而promise就为我们提供了一种优雅的方式来解决上述问题。
2.Promise的好处
2.1我们使用setTimeout函数来模拟网络请求进行分析
(1)普通网络请求写法:
<script type="text/javascript">
setTimeout(() =>{
console.log("第一次数据请求成功后处理的代码");
setTimeout(() =>{
console.log("我是第二次数据请求成功后处理的代码");
setTimeout(() =>{
console.log("我是第三次数据请求成功后处理的代码");
},1000)
},1000)
},1000)
</script>
(2)运用promise:
<script type="text/javascript">
new Promise((resolve,reject) =>{
//第一次网络请求的代码
setTimeout(() =>{
resolve();
},1000);
}).then(() =>{
console.log("第一次请求成功后处理的代码");
return new Promise((resolve,reject) =>{
//第二次请求数据的代码
setTimeout(() =>{
resolve();
})
}).then(() =>{
console.log("第二次请求成功处理的代码");
return new Promise((resolve,reject) =>{
//第三次请求数据的代码
setTimeout(() =>{
resolve();
})
}).then(() =>{
console.log("第三次请求成功后处理的代码");
})
})
})
总对比上述两种写法,部分人看到写法二的代码较多所以认为第一种写法比较好,但是仔细阅读Promise写法,你会发现它不像写法一存在嵌套调用的写法,每一个promise都有自己发送请求和请求成功后独立处理相关代码的地方,这样的写法逻辑清晰且代码易于维护。
3.Promise详析
3.1 Promise的三种状态
1.pending:等待状态,比如在进行网络请求,或者定时器没有到时间
2.fufill:满足状态,当我们主动调用resolve时,就处在该状态,并且会调用.then()
3.reject:拒绝状态,当我们主动调用reject时,我们就处在该状态,并会回调.catch()
4.代码基本结构:
(1)写法一:
<script type="text/javascript">
new Promise((resolve,reject) =>{
//第一次网络请求的代码
setTimeout(() =>{
resolve('request data');//resolve和reject不能同时写
//reject('error data');
},1000);
}).then((data) =>{
console.log(data);
}).catch((error) =>{
console.log(error);
})
</script>
(2)写法二:
script type="text/javascript">
new Promise((resolve,reject) =>{
//第一次网络请求的代码
setTimeout(() =>{
resolve('request data');
//reject('error data');
},1000);
}).then((data) =>{
console.log(data);
},(error) =>{
console.log(error);
})
</script>
3.2 Promise的链式调用
PS:此代码描述的功能为,对第一次请求的数据进行处理,处理结束后传递给下一层,让下一层在进行处理,最终返回(此处代码只写了第一次处理,下一层处理与该层处理操作类似)
(1)基本写法:
<script type="text/javascript">
new Promise((resolve,reject) =>{
//第一次网络请求的代码
setTimeout(() =>{
resolve('request data');
//reject('error data');
},1000);
}).then((data) =>{
console.log(data);
return new Promise(resolve =>{
resolve(data +''+ "1111");
}).then((res) =>{
console.log(res);
return
}).catch(error =>{
console.log(error);
})
})
</script>
(2)上述代码的两种简写方式:
我们在看Promise的流程图时,发现无论是then还是catch都可以返回一个Promise对象,所以我们的代码其实是可以直接进行链式调用的
-promise.resolve():将函数包装成新的Promise对象,并且在内部调用resolve()函数
-promise.reject():将函数包装成Promise对象,并且在内部调用reject()函数
<script type="text/javascript">
new Promise((resolve,reject) =>{
//第一次网络请求的代码
setTimeout(() =>{
resolve('request data');
//reject('error data');
},1000);
}).then((data) =>{
console.log(data);
return Promise.resolve(data +" "+"1111");
//return Promise.reject('error data');
// throw "error message";
}).then((res) =>{
console.log(res);
}).catch(error =>{
console.log(error);
})
</script>
<script type="text/javascript">
new Promise((resolve,reject) =>{
//第一次网络请求的代码
setTimeout(() =>{
resolve('request data');
//reject('error data');
},1000);
}).then((data) =>{
console.log(data);
return data +" "+"1111";
}).then((res) =>{
console.log(res);
}).catch(error =>{
console.log(error);
})
</script>
3.3 Promise的All方法
如果我们同时需要发送两个不同的网络请求才能完成某个功能时,我们可以使用Promise.All方法来简单有效的实现此需求
<script type="text/javascript">
Promise.all([
new Promise((resolve,reject) =>{
setTimeout(() =>{
resolve('requqst1 data');
},1000)
}),
new Promise((resolve,reject) =>{
setTimeout(() =>{
resolve('requqst2 data');
},1000)
})
]).then(res =>{
console.log(res[0]);
console.log(res[1]);
})
</script>