博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Promise实现思路的个人理解
阅读量:7104 次
发布时间:2019-06-28

本文共 4323 字,大约阅读时间需要 14 分钟。

Promise实现思路的个人理解

我一直觉得Promise虽然方便,但是它的写法很怪,无法理解实现Promise的人是如何思考的。

不过最近我对于实现Promise的思考过程的有了一点点个人理解,特此记下。

感觉这篇文章我还是没有把思路说清楚,时间紧张,就当做一次记录,回头我要把这个过程在表达的在清楚一点。

用例
var p1 = new Promise2( ( resolve, reject ) => {            setTimeout( () => {                resolve( 'hello' )            }, 1000 )        } )        p1.then( res => {                console.log( res + 'world' )                return res + 'world'            } )            .then( res => {                console.log( res + 'ziwei' )                return res + 'ziwei'            } )

我觉得实现一个函数跟封装组件类似,首先从以下几点考虑:

  • 1.这个函数用来做什么的?
  • 2.接受哪些参数
  • 3.返回值是什么

那么结合例子,和这几个问题,我们得到

  • 1.Promise是做异步流程控制的。通俗说就是,我希望某个函数暂时不执行,等我希望它执行时,就resolve一下,你这个函数在执行。
  • 2.构造函数Promise接受一个函数。函数的参数是resolve,reject,resolve和reject也是函数,是给用户调用用的,当用户希望下一个异步执行时,就调用resolve(0
  • 3.返回一个promise实例。 promise实例都有一个then方法,而then方法也返回一个新的promise实例。由此就可以链式调用then了
先实现一个Promise(未实现then的链式调用)
  • 1.Promise接受一个fn,不管其他,你觉得这个fn在内部会干嘛?只能被调用呗,所以虽然不知道怎么搞,但是先调用一下fn(resolve,reject)
  • 2.那这个resolve和reject不是用户实现的,所以肯定是Promise开发者实现的,那我们要实现resolve和reject,它们是干嘛的,肯定用来是改变状态的,所以定义this.state
  • 3.resolve和reject也会接受用户的参数吧,那我们就需要把这个参数用this.value缓存一下,将来then方法调用时,需要传递进去
  • 4.then接受successFn和errorFn,这2个就是我们希望暂时不执行的函数了。怎么做到暂时不执行呢?就是声明2个数组,把他们先存起来,将来resolve时,在调用
class Promise2 {            constructor( fn ) {                this.successFnArray = []  // 用来缓存successFn和errorFn                this.errorFnArray = []                this.state = 'pendding'                const resolve = ( res ) => {      // resolve就做2件事情  1: 修改状态 2:调用successFn                    this.state = 'fulfilled'                    this.value = res         // this.value用来缓存data数据或者error                    this.successFnArray.forEach( successFn => {                        successFn( res )                    } )                }                const reject = ( err ) => {                    this.state = 'rejected'                    this.value = err                    this.errorFnArray.forEach( errorFn => {                        errorFn( res )                    } )                }                fn( resolve, reject )   // 先调用fn再说            }            then( successFn, errorFn ) {                switch ( this.state ) {                    case 'fulfilled':                        successFn( this.value )        // 如果调用了resolve,状态就成了fulfilled,就会执行successFn                        break                    case 'rejected':                        errorFn( this.value )                        break                    case 'pendding':                        this.successFnArray.push( successFn )   // 如果还没调用resolve,状态就是pendding,就先把这些异步函数缓存起来。将来resole时调用                        this.errorFnArray.push( errorFn )                }            }        }        var p1 = new Promise2( ( resolve, reject ) => {            setTimeout( () => {                resolve( 'hello' )            }, 1000 )        } )        p1.then( res => {            console.log( res + 'world' )            return res + 'world'        } )
实现then链式调用

then的实现,和JQ的链式调用不同,JQ是每次调用方法后,把this返回

而Promise规范要求,每次都要返回新的Promise对象

所以只需要把then方法修改一下。

这部分可能会迷惑,但是我想先说一下这里做了哪些事情,其实变化不大

之前的then做了哪些事情?

  • 就是按照不同的state,调用了successFn或者errorFn,如果是pendding状态就先缓存起来,等将来resolve时调用

链式then有哪些改动?

  • 首先then有了返回值,返回一个promise,而之前没有返回值,return的是undefined
  • new Promise的过程,其实逻辑没什么变化,唯一注意的,比如状态fulfilled时,并非直接调用successFn

而是调用_successFn,而这个函数内部本质上还是调用successFn(),但同时把调用的返回值作为了resolve的参数,调用了resolve()

因为当successFn被调用,得到返回值时,就表示这个函数执行完了,

就需要执行下一个异步函数了,这样下一个异步函数也会把successFn(res)的return值作为参数

then( successFn, errorFn ) {                                return new Promise2( ( resolve, reject ) => {                    const _successFn = res => {                        resolve(successFn(res))                    }                    const _errorFn = err => {                        reject(errorFn(err))                    }                                        switch ( this.state ) {                        case 'fulfilled':                        _successFn( this.value )                            break                        case 'rejected':                        _errorFn( this.value )                            break                        case 'pendding':                            this.successFnArray.push( _successFn )                            this.errorFnArray.push( _errorFn )                    }                } )            }

转载地址:http://gzuhl.baihongyu.com/

你可能感兴趣的文章
c++大文件读写操作(文件内存映射)
查看>>
nginx 主动防御DDOS***
查看>>
JS学习笔记
查看>>
linux sed seq awk 部分
查看>>
oracle删除168万数据;varchar表示时间;java传参date;传参后的时间保存到秒
查看>>
冰箱保鲜标准出炉,行业或迎新纪元
查看>>
十三、添加RD 会话主机角色
查看>>
Android笔记--一个图片+文字的自定义按钮
查看>>
Android/Java 读、写MP3文件ID3V1信息
查看>>
企业开展智能制造,将会存在和带来哪些风险?
查看>>
从Kubernetes 1.14 发布,看技术社区演进方向
查看>>
PHP源码:方维o2o本地生活服务系统v2.2多城市商业版
查看>>
Websense:Android的安全性令人担忧
查看>>
Office 365 系列之四:添加自定义域
查看>>
Android应用程序启动过程——Launcher源码分析
查看>>
(实战)从关联表中取得JSON数据
查看>>
maven添加repository仓库
查看>>
vSAN 6.0设计与规模设定——vSAN设计概览
查看>>
zabbix邮件报警之完整总结
查看>>
我的友情链接
查看>>