Promise
大家都知道Promise称之为异步神器,解决了困扰我们的回调地狱,所以因此很多面试过程中都会让你手写一个Promise函数,Promise三个状态, PENDING=>等待 resolved =>成功 rejected=>失败
一、简单的手写
var promise = new Promise((resolve,reject) => {
if(操作成功){
resolve(value)
}
else{
reject(error)
}
})
promise.then(v=>{
console.log(v)
})
二、复杂手写
new Promise((resolve,reject) =>{
console.log('cc')
setTimeout(()=>{
// resolve(new Promise(res =>{
// console.log('ss')
// res(520) //向下传递520
// })
// )
resolve(666) //向下传递666
},1000)
}).then(res => {
console.log(res) //上面继续resolve(new Promise时)传递520, 直接resolve接收666
return 521 //向下传递
}).then(res => {
console.log(res); //521
})
打印结果
/*
cc
延迟一秒后
666
521
*/
三、用class 手写一个Promise
//创建一个Promise的类
class MyPromise {
constructor(fn){
this.res = null;
this.err = null;
this.status = 'PENDING';
this.onResolveCallbacks = [];//存放成功的回调
this.onRejectCallbacks = [];//存放失败的回调
try {
fn((res) => {
this.status = 'resolved';
this.res = res;
this.onResolveCallbacks.forEach(fn => fn())
}, (err) => {
this.status = 'rejected';
this.err = err
this.onRejectCallbacks.forEach(fn => fn())
})
} catch (error) {
console.log(error)
}
}
//成功的回调函数
then(onFulfilled, onRejected) {
let self = this;
if (this.status === 'resolved') {//成功
onFulfilled(self.res);
}
if (this.status === 'rejected') {//失败
onRejected(self.err);
}
//如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
//这里主要是为了处理异步的操作 比如加上setTimeout 时 需要这里 如果没有setTimeout它可直接执行
if (this.status === 'PENDING'){
this.onResolveCallbacks.push(()=>{
onFulfilled(self.res)
})
this.onRejectCallbacks.push(() => {
onFulfilled(self.err)
})
}
//
}
}
new MyPromise((resolve,reject) => {
setTimeout(()=>{
resolve(666)
},1000)
}).then(res=>{
console.log(res) //成功打印666
})
用函数手写一个Promise(面试时手写这个)
<script>
function Promise(exector) {
let self = this;
//status表示一种状态
let status = "pending";
let value = undefined;
let reason = undefined;
//成功执行
function resolve(value) {
if (status == 'pending') {
self.value = value;
self.status = "resolve";
}
}
//执行失败
function reject(reason) {
if (status == 'pending') {
self.reason = reason;
self.status = "reject"
}
}
//对异常操作
try {
exector(resolve, reject)
} catch (e) {
reject(e)
}
//设置promise的then方法
Promise.prototype.then = function(reject, resolve) {
let self = this;
if (this.status == 'resolve') {
resolve(self.value)
}
if (this.status == 'reject') {
reject(self.reason)
}
}
}
let promise = new Promise((reject, resolve) => {
resolve(520);
});
promise.then(res => {
console.log(`success:${res}`);
}, err => {
console.log(`err:${err}`);
})
</script>
实际使用场景
将API用Promise封装
UNIAPP的封装
/*封装request接口*/
const BASE_URL = 'http://localhost:8082'
export const myRequest = (options)=>{
return new Promise((resolve,reject)=>{
uni.request({
url:BASE_URL+options.url,
method:options.method || 'GET',
data:options.data || {},
success: (res)=>{
if(res.data.status !== 0){
return uni.showToast({
title:'获取数据失败'
})
}
resolve(res)
},
fail: (err)=>{
uni.showToast({
title: '获取数据失败'
})
reject(err)
}
})
})
}
-----------调用举例------------
async getHotGoods (){
const res = await this.$myRequest({ //直接拿myRequest
url:'/api/getgoods?pageindex=1'
})
console.log(res)
this.goodsarr = res.data.message
}
小程序的封装
// 同时发送异步代码的次数
let ajaxTimes = 0;
export const request=(params)=>{
//判断url是否带有 /my/ 请求的是私有的路径 带上header token
let header={...params.header}; //解构了旧的,再可以带上新的请求头信息
if(params.url.includes("/my")){
// 拼接header 带上token
header["Authorization"] = wx.getStorageSync('token')
}
ajaxTimes++;
//显示加载中的效果
wx.showLoading({
title: '加载中',
mask:true,
})
//定义公共的url
const baseUrl="xxx"
return new Promise((resolve,reject)=>{
wx.request({
...params,
header:header,
url:baseUrl+params.url,
success:(result)=>{
resolve(result.data.message);
},
fail:(err)=>{
reject(err);
},
complete:()=>{
ajaxTimes--;
if(ajaxTimes===0){
wx.hideLoading()
}
}
});
})
}
-----------例子调用--------------
async getGoodsList(){
const res = await request({
url:"/goods/search",
data:this.QueryParams
});
}