深度解析利用ES6进行Promise封装总结
这篇文章主要介绍了如何利用ES6进行Promise封装总结,文中通过示例代码介绍的非常详细,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。
原生Promise解析
简介
- promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和强大。
- promise简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,从语法上来说,Promise是一个对象,从它可以获取异步操作的消息,Promise提供统一的API,各种异步操作都可以用同样的方法进行处理
特点
对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:Pendding、fulfilled、rejected。只有异步操作的结果,可以决定当前是哪一种状态,其他操作都无法改变这个状态。 一旦状态改变,就不会在变,任何时候都可以得到这个结果,只有两种可能:从Pendding变为fulfilled和从Pendding变为rejected。只要这两种情况发生,状态就凝固了,会一直保持这个结果,这时就称为resolved。 1.利用es6进行Promise封装
2.处理同步任务
3.原生方法调用方式
new Promise((resolve,reject)=>{
resolve(1)
}).then(res=>{
console.log(res) //1
})
同步封装思考 1.由调用方式可见Promise是一个类 2.它接收一个回调函数,这个回调函数接受resolve和reject方法作为参数 3.当状态改变后执行then方法,并将resolve或reject的结果作为then方法接受回调函数的参数
class Mypromise{
constructor(callback){
this.status='pendding'
//成功结果
this.s_res = null
// 失败结果
this.f_res = null
callback((arg)=>{ // 使用箭头函数this不会丢失
// 改变状态为成功
this.status = 'fulfilled'
this.s_res = arg
},(arg)=>{
// 改变状态为失败
this.status = 'rejected'
this.f_res = arg
})
}
then(onresolve,onreject){
if(this.status === 'fulfilled'){ // 当状态为成功时
onresolve(this.s_res)
}else if(this.status === 'rejected'){ // 当状态为失败时
onreject(this.f_res)
}//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
}
}
处理异步任务
原生调用方式
new Promise((resolve,reject)=>{
setTimeOut(()=>{
resolve(1)
},1000)
}).then(res=>{
console.log(res)
})
异步封装思考 1.根据js执行机制,setTimeOut属于宏任务,then回调函数属于微任务,当主线程执行完成后,会从异步队列中取出本次的微任务先执行。 2.也就是说,then方法执行时,状态还没有改变,所有我们需要将then方法执行的回调保存起来,等到异步代码执行完成后,在统一执行then方法的回调函数
class Mypromise{
constructor(callback){
this.status='pendding'
//成功结果
this.s_res = null
// 失败结果
this.f_res = null
this.query = [] // ++
callback((arg)=>{ // 使用箭头函数this不会丢失
// 改变状态为成功
this.status = 'fulfilled'
this.s_res = arg
// 当状态改变后,统一执行then方法的回调
this.query.forEach(item=>{
item.resolve(arg)
})//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
},(arg)=>{
// 改变状态为失败
this.status = 'rejected'
this.f_res = arg
// 当状态改变后,统一执行then方法的回调
this.query.forEach(item=>{
item.reject(arg)
})
})
}
then(onresolve,onreject){
if(this.status === 'fulfilled'){ // 当状态为成功时
onresolve(this.s_res)
}else if(this.status === 'rejected'){ // 当状态为失败时
onreject(this.f_res)
}else{ // ++ 状态没有改变
this.query.push({ // 保存回调函数到队列中
resolve:onresolve,
reject:onreject
})//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
}
}
}
处理链式调用
原生调用方式
new Promise((resolve,reject)=>{
resolve(1)
}).then(res=>{
return res
}).then(res=>{
console.log(res)
})//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
链式调用思考
原生的Promise对象的then方法,返回的也是一个Promise对象,一个新的Promise才能支持链式调用 下一个then方法可以接受上一个then方法的返回值作为回调函数的参数 主要考虑上一个then方法的返回值: 1.Promise对象/具有then方法的对象 2.其他值 第一个then方法返回一个Promise对象,它的回调函数接受resFn和rejFN两个回调函数作为参数,把成功状态的处理封装为handle函数,接受成功的结果作为参数 在handle函数,根据onresolve返回值的不同做出不同的处理
class Mypromise{
constructor(callback){
this.status='pendding'
//成功结果
this.s_res = null
// 失败结果
this.f_res = null
this.query = [] // ++
callback((arg)=>{ // 使用箭头函数this不会丢失
// 改变状态为成功
this.status = 'fulfilled'
this.s_res = arg
// 当状态改变后,统一执行then方法的回调
this.query.forEach(item=>{
item.resolve(arg)
})
},(arg)=>{
// 改变状态为失败
this.status = 'rejected'
this.f_res = arg
// 当状态改变后,统一执行then方法的回调
this.query.forEach(item=>{
item.reject(arg)
})
})
}
then(onresolve,onreject){
return new Mypromise((resFN,rejFN)=>{
if(this.status === 'fulfilled'){ // 当状态为成功时
handle(this.s_res)
}else if(this.status === 'rejected'){ // 当状态为失败时
errBack(this.f_res)
}else{ // ++ 状态没有改变
this.query.push({ // 保存回调函数到队列中
resolve:onresolve,
reject:onreject
})
} //在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
function handle(value){
// 当then方法的onresolve方法有返回值时,保存其返回值,没有使用其保存的值
let returnVal = onresolve instanceof Function && onresolve(value) || value
// 如果onresolve方法返回的是promise对象,则调用其then方法
if(returnVal&&returnVal['then'] instanceof Function){
returnVal.then(res=>{
resFN(res)
},err=>{
rejFN(err)
})
}else{
resFN(returnVal)
}
}
function errBack(reason){
if(onreject instanceof Function){
let returnVal = reject(reason)
if(typeof returnVal !== 'undenfined' && returnVal['then'] instanceof Function){
returnVal.then(res=>{
resFN(res)
},err=>{
rejFN(err)
})
}else{
resFN(returnVal)
}
}else{
rejFN(reason)
}
}
})
}
}
Promise.all和Promise.race方法
原生调用方式 Promise.all方法接受一个数组,数组中的每一项都是一个Promise实例,只有数组中的所有Promise实例的状态都变为fulfilled时,此时整个状态才会变成fulfilled,此时数组中所有Promise实例的返回值组成一个新的数组,进行传递。 Promise.race方法和Promise.all方法一样,如果不是Promise实例,就会先调用Promise.resolve方法,将参数转为Promise实例,在进行下一步处理。 只要数组中有一个参数的状态变为fulfilled就会进行传递
// 将现有对象转换为Promise对象
Mypromise.resolve = (arg)=>{
if(typeof arg == 'undefined' || arg==null){ // 不带有任何参数
return new Mypromise(resolve=>{
resolve(arg)
})
}else if(arg instanceof Mypromise){ // 是一个Mypromise实例
return arg
}else if(arg['then'] instanceof Function){ // 具有then方法的对象
return new Mypromise((resolve,reject)=>{
arg.then(res=>{
resolve(res)
},err=>{
reject(err)
})//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
})
}else{ // 参数不是具有then方法的对象,或根本不是对象
return new Mypromise(resolve=>{
resolve(arg)
})
}
}
Mypromise.all = (arr)=>{
if(!Array.isArray(arr)){
throw new TypeError('参数必须是一个数组')
}
return new Mypromise((resolve,reject)=>{
let i=0,result=[]
next()
functon next(){
// 如果不是Mypromise实例需要转换
Mypromise.resolve(arr[i]).then(res=>{
result.push(res)
i++
if(i===arr.length){
resolve(result)
}else{
next()
}
},reject)
}
})
}//在此我向大家推荐一个前端全栈开发交流圈:619586920 突破技术瓶颈,提升思维能力
Mypromise.race = (arr)=>{
if(!Array.isArray(arr)){
throw new TypeError('参数必须是一个数组')
}
return new Mypromise((resolve,reject)=>{
let done = false
arr.forEach(item=>{
Mypromise.resolve(item).then(res=>{
if(!done){
resolve(res)
done = true
}
},err=>{
if(!done){
reject(res)
done = true
}
})
})
})
}
处理Mypromise状态确定不能改变的特性 在重写callback中的resolve和reject方法执行前,先判断状态是否为'pendding'
结语
感谢您的观看,如有不足之处,欢迎批评指正。
关注公众号
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门
Spring 5.0 中发布了重量级组件 Webflux,拉起了响应式编程的规模使用序幕。 WebFlux 使用的场景是异步非阻塞的,使用 Webflux 作为系统解决方案,在大多数场景下可以提高系统吞吐量。Spring Boot 2.0 是基于 Spring5 构建而成,因此 Spring Boot 2.X 将自动继承了 Webflux 组件,本篇给大家介绍如何在 Spring Boot 中使用 Webflux 。 为了方便大家理解,我们先来了解几个概念。 响应式编程 在计算机中,响应式编程或反应式编程(英语:Reactive programming)是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。 例如,在命令式编程环境中,a=b+c 表示将表达式的结果赋给 a,而之后改变 b 或 c 的值不会影响 a 。但在响应式编程中,a 的值会随着 b 或 c 的更新而更新。 响应式编程是基于异步和事件驱动的非阻塞程序,只需要在程序内启动少量线程扩展,而不是水平通过集群扩展。 用大白话讲,我们以...
-
下一篇
Dojo 表单校验
tutorials/1015_form_validation/index.md commit 3e0f3ff1ed392163bc65e9cd015c4705cb9c586e {% section 'first' %} 表单校验 Overview 本教程将介绍如何在示例应用程序的上下文中处理基本的表单校验。在 注入状态 教程中,我们已经介绍了处理表单数据;我们将在这些概念的基础上,在现有表单上添加校验状态和错误信息。本教程中,我们将构建一个支持动态的客户端校验和模拟的服务器端校验示例。 前提 你可以打开 codesandbox.io 上的教程 或者 下载 示例项目,然后运行 npm install。 本教程假设你已经学习了 表单部件教程 和 状态管理教程。 {% section %} 创建存储表单错误的对象 {% task '在应用程序上下文中添加表单错误。' %} 现在,错误对象应该对应存在于 WorkerForm.ts 和 ApplicationContext.ts 文件中的 WorkerFormData。这种错误配置有多种处理方式,一种情况是为单个 input 的多个校验步骤分别...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- MySQL数据库中FOR UPDATE的使用
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker容器配置,解决镜像无法拉取问题
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS6,CentOS7官方镜像安装Oracle11G


微信收款码
支付宝收款码