Promise封装方式

下面用到模块化的相关知识,如果不是很了解,可以参考另一篇文章:

https://blog.csdn.net/zxd1435513775/article/details/106334253

1. Promise的基本介绍

Promise在ES6中被列为正式规范,是ES6中最重要的特性之一。

下面在Chrome的控制台中,输入console.dir(Promise),见下图:

在这里插入图片描述

从上图中,可以看出

  • Promise是一个构造函数,自己身上有all、reject、resolve这几个方法
  • 原型上有then、catch等方法
  • 用Promise new出来的对象肯定就有then、catch方法

简单使用

// 1. 创建一个新的promise对象
const p = new Promise(function(resolve, reject) {// 执行器函数  同步回调
    console.log('执行 excutor')
    // 2. 执行异步操作任务
    setTimeout(() => {
        const time = Date.now() // 如果当前时间是偶数就代表成功, 否则代表失败
        // 3.1. 如果成功了, 调用resolve(value)
        if (time %2 == 0) {
            resolve('成功的数据, time=' + time)
        } else {
            // 3.2. 如果失败了, 调用reject(reason)
            reject('失败的数据, time=' + time)
        }
    }, 1000);
})

console.log('new Promise()之后')

p.then(
    value => { // 接收得到成功的value数据
        console.log('成功的回调', value)  
    },
    reason => {// 接收得到失败的reason数据
        console.log('失败的回调', reason)
    }
)

p.catch(() => {
    console.log('catch...')
})
  • 实例化Promise时有两个回调函数,resolve、reject,成功执行resolve,失败执行reject
  • 在实例化p的then中有两个对应的回调函数,第一个回调是resolve执行时触发,第二个回调是reject执行时触发
  • p.then()返回是Promise类型,p.catch()返回是Promise类型

then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调,能够分别拿到它们传过来的数据

我们知道Promise对象除了then方法,还有一个catch方法,它是做什么用的呢?

其实它和then的第二个参数一样,用来指定reject的回调,用法是这样:

p.then(
    function (value) {
        // 接收得到成功的value数据 
        console.log('成功的回调', value)
        //此处输入一个未定义的变量,如果没有catch(),则会报错,后面都不会执行,卡死在这
        console.log(ssss)  
        console.log('成功的回调11', value)
    },
    function (reason) {
        console.log('失败的回调', reason)
    }
)

p.catch((reason) => {
    console.log('catch...')
})

效果和写在then的第二个参数里面一样。不过它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。

2. Promise的初封装

import axios from 'axios';

let baseURL; // process.env.NODE_ENV环境
if(process.env.NODE_ENV=='development'){
    baseURL = 'http://127.0.0.1:3000/api'
}else{
    baseURL = '/xxx'
}

const $http = axios.create({
    baseURL,
})

// 分别暴露
export const get = (url,params)=>{
    params = params || {};
    return new Promise((resolve,reject)=>{
        // axiso 自带 get 和 post 方法
        $http.get(url,{
            params,
        }).then(res=>{
            if(res.data.status===0){
                resolve(res.data);
            }else{
                alert(res.data.msg)
            }
        }).catch(error=>{
            alert('网络异常');
        })
    })
}

export const post = (url,params)=>{
    params = params || {};
    return new Promise((resolve,reject)=>{
        $http.post(url,params).then(res=>{
            if(res.data.status===0){
                resolve(res.data);
            }else{
                alert(res.data.msg);
            }
        }).catch(error=>{
            alert('网络异常');
        })
    })
}

如何引用呢?

import { get, post } from "./utils/index";
Vue.prototype.$http = {
  get,
  post
};

这里使用了构造函数的原型prototype声明一个全局变量,并且把封装好的get和post方法放在里面

3. Promise再封装

3.1 第一版封装

目录结构

├── common
│   ├── api
│   │   └── index.js
├── main.js

main.js

import App from './App'
import api from "./common/api"  // 导入/common/api/index.js文件
import Vue from 'vue'

Vue.config.productionTip = false
Vue.prototype.$api = api
App.mpType = 'app'
const app = new Vue({
    ...App
})
app.$mount()

index.js

const getLabel = (data) => {
	return new Promise((resolve,reject)=>{
        // 此处可以换成其他任何发送请求的方式,如:ajax,axios都可以的
		uniCloud.callFunction({
			name:'getLabel',
			data
		}).then((res)=>{
			if(res.result.code === 200){
				resolve(res.result)
			}else{
				reject(res.result)
			}
		}).catch((err)=>{
			reject(err)
		})
	})
}

// 默认导出
export default{
    getLabel
}

在其他地方就可以使用如下方式调用getLabel()这个方法了:

this.$api.getLabel().then((res)=>{
    console.log('getLabel',res)
})

上面这个版本,是将所有的请求方法都放在index.js这一个文件里,随着方法的增多,这个文件肯定会越来,不易于维护。下面就可以按模块,将各个模块的请求方法放到自己的文件中,然后在index.js这个文件中进行汇总,来看看吧。

3.2 第二版封装

目录结构如下:

├── common
│   ├── api
│   │   └── index.js
│   │   └── list.js
├── main.js

list.js

// 使用分别暴露
export const getLabel = (data) => {
	return new Promise((resolve,reject)=>{
		uniCloud.callFunction({
			name:'getLabel',
			data
		}).then((res)=>{
			if(res.result.code === 200){
				resolve(res.result)
			}else{
				reject(res.result)
			}
		}).catch((err)=>{
			reject(err)
		})
	})
}

export const getList = (data) => {
	return new Promise((resolve,reject)=>{
		resolve({data:"请求成功"})
	})
}

index.js

// 在index.js中引入list.js,再暴露出来,其他模块也可以这样的方式引入
import {getLabel,getList} from './list.js';

export default{
	getLabel,
	getList
}

使用

methods: {
	getLabel(){
        // 调用请求
		this.$api.getList().then((res)=>{
			console.log('getList',res)
		})
        
		this.$api.getLabel().then((res)=>{
			console.log('getLabel',res)
		})
	}
}

3.3 第三版封装

对于第二个版本,按模块去封装对应的请求方法,这个是没问题的,但是需要手动的在index.js文件中引入,是不是这一步也是有点多余呢?下面就来在index.js中自动引入所有的模块请求函数。

目录结构:

├── common
│   ├── api
│   │   └── index.js
│   │   └── list.js
│   ├── http.js
├── main.js

index.js

// 批量导出文件
const requireApi = require.context(
	// api 目录的相对路径
	'.',
	// 是否查询子目录
	false,
	// 查询文件的一个后缀
	/.js$/
)

let module = {}
// console.log(requireApi.keys()) 当前目录下的所有文件
requireApi.keys().forEach((key,index)=>{
	if(key === './index.js') return
	// console.log(key);
	// console.log('requireApi(key)',requireApi(key))
	Object.assign(module,requireApi(key))
})
// console.log('module',module)
export default module

把上面的注释打开,输出是这样的:

在这里插入图片描述

list.js

import $http from '../http.js'

export const getLabel = (data) => {
	return $http({
		url: 'getLabel',
		data
	})
}

export const getList = (data) => {
	return $http({
		url: 'getList',
		data
	})
}

http.js

export default function $http(options) {
	// 结构赋值
    const {	url, data } = options
	return new Promise((reslove, reject) => {
		uniCloud.callFunction({
			name: url,
			data
		}).then((res) => {
			if (res.result.code === 200) {
				reslove(res.result)
			} else {
				reject(res.result)
			}
		}).catch((err) => {
			reject(err)
		})
	})
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

止步前行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值