一步一步实现一个promisea+规范的promise

homehtml homehtml     2022-12-23     430

关键词:

2015年6月,ES2015(即ES6)正式发布后受到了非常多的关注。其中很重要的一点是 Promise 被列为了正式规范。
在此之前很多库都对异步编程/回调地狱实现了类 Promise 的应对方案,比如 bluebird、Angular 的 Q 和大名鼎鼎的 jQuery 的 deffered 等。

为了便于理解,本文将分为三个部分,每个部分实现 Promise 的一部分特性,最终一步一步的实现一个完整的、遵循 promise A+ 规范的 Promise。

Promise A+ 规范规定,Promise 有三种状态,分别是 pending(默认状态,代表等待)、fulfilled(代表成功)、rejected(代表失败)。

来看看 Promise 的用法,以及它有哪些特性。

var fn = new Promise(function (resolve, reject)     
    // 异步操作    
    setTimeout(function()         
        resolve(‘resolve 01‘)        
        // 由于reslove和 reject 是互斥的,因为已经调用了 resolve,这里reject不会执行 
        reject(‘reject 01‘)
    , 500)
)
fn().then(function (data) 
    console.log(‘成功1:‘, data)
    return new Promise(function (resolve, reject) 
        reject(‘reject 02‘)
    
), function (err) 
    console.log(‘失败1:‘, err)
)
.then(function (data) 
    console.log(‘成功2:‘, data)
, function (err) 
    console.log(‘失败2:‘, err)
).then(function (data) 
    console.log(‘成功2:‘, data), function (err) 
    console.log(‘失败2:‘, err)
)

结果:

技术图片

可以看到,Promise 通常会有这些特性:

①、Promise 类有 then 方法,then 方法有两个参数,分别是 Promise 成功和失败的回调,且二者互斥,调用了其中一个,另外一个就不会执行

②、Promise 支持链式调用,then 的返回值可以是一个 Promise,也可以是一个普通值,如果是 一个普通的值,那么就会当做下一个 then 成功的回调函数的参数

③、Promis 还有其它扩展方法

说了一堆有的没的,下面就开始来实现这个东西吧~

=================================================

一,Promise 类的实现

=> Promise 有 then 方法:

var Promise = function (executor) 
    console.log(‘证明不是用的原生 Promise‘)
    var _this = this
    this.status = ‘pending‘
     // 默认状态,可以转化为 resolved 和 rejected
    this.successVal = undefined
    this.failVal = undefined

    // 执行了成功或失败后,要将状态对应修改成成功和失败
    function resolve (val) 
        if ( _this.status === ‘pending‘ ) 
            _this.status = ‘resolved‘
            _this.successVal = val
        
    
    function reject (val) 
        if ( _this.status === ‘pending‘ ) 
            _this.status = ‘rejected‘
            _this.failVal = val
        
    

    try 
        // 应该还记得,Promise 的参数是一个函数吧,我们称之为 executor(执行器)
        // 同时这个函数接收2个参数,分别是成功和失败的回调函数
        executor(resolve, reject)
     catch (e) 
        // 如果发生异常,直接reject捕获
        reject(e)
    

// then 方法接收2个参数,分别是成功和失败的回调函数
Promise.prototype.then = function (onFulfilled, onRejected) 
    var _this = this    
    // 显然要根据当前状态来执行成功或失败的回调了
    if ( _this.status === ‘resolved‘ ) 
        onFulfilled(_this.successVal)
    
    if ( _this.status === ‘rejected‘ ) 
        onFulfilled(_this.failVal)
    
来试试效果:

var fn = new Promise(function (resolve, reject) 
    resolve(‘oooook~‘)
) 
fn.then(function (data) 
    console.log(‘success: ‘, data), function (err) 
    console.log(‘err: ‘, err)
)

结果:

技术图片

结果看上去很美。但如果改成下面这样呢?

var fn = new Promise(function (resolve, reject) 
    setTimeout(function () 
        resolve(‘oooook~‘)
    , 500)
) 
fn.then(function (data) 
    console.log(‘success: ‘, data)
, function (err) 
    console.log(‘err: ‘, err)
)
结果:

技术图片

ok,问题来了,Promise 费大力气搞出来可不是只能做同步调用的,毕竟有了 ajax 之后前端才会发展到今天这么繁荣,所以需要让我们的 Promise 支持异步。

修改如下(注释内是对新增代码的说明):

var Promise = function (executor) 
    console.log(‘证明不是用的原生 Promise 的一句废话‘)
    var _this = this    this.status = ‘pending‘
     // 默认状态,可以转化为 resolved 和 rejected
    this.successVal = undefined
    this.failVal = undefined
    // ----------------- 表示新增代码 --------------------    // 用于存放成功和失败的回调
    this.onFulfilledList = []
    this.onRejectedList = []

    function resolve (val) 
        if ( _this.status === ‘pending‘ ) 
            _this.status = ‘resolved‘
            _this.successVal = val
            // -------------- 执行所有的成功回调 ---------------
            _this.onFulfilledList.forEach(function(fn)
                fn()
            )
        
    
    function reject (val) 
        if ( _this.status === ‘pending‘ ) 
            _this.status = ‘rejected‘
            _this.failVal = val
            // -------------- 执行所有的失败回调 ---------------
            _this.onRejectedList.forEach(function(fn)
                fn()
            )
        
    
    try 
        executor(resolve, reject)
     catch (e) 
        reject(e)
    

Promise.prototype.then = function (onFulfilled, onRejected) 

    var _this = this

    if ( _this.status === ‘resolved‘ ) 
        onFulfilled(_this.successVal)
    
    if ( _this.status === ‘rejected‘ ) 
        onFulfilled(_this.failVal)
    

    // ----------------- 对异步调用的处理 -------------------
    // 说明:如果是异步调用,走到 then 方法里的时候,status 还没有被修改,仍然
    // 是 pending 状态,所以这时候需要再回去执行 executor 里的对应方法,而对应的
    // 方法会将对应的存放回调的 list 里的方法执行(类似发布-订阅模式一样的处理)
    if ( _this.status === ‘pending‘ ) 
        _this.onFulfilledList.push(function () 
            onFulfilled(_this.successVal)
        )
        _this.onRejectedList.push(function () 
            onRejected(_this.failVal)
        )
    
看看效果:

技术图片

目前来看已经支持异步了~


听说你们都在黑我大星爵?星爵那么萌,你们忍心吗

技术图片


下一篇:一步一步来实现一个Promise A+规范的 Promise之二:Promise 链式调用


















一步一步学习jni(代码片段)

本文来自网易云社区作者:孙有军前言本篇的主要目的就是JNI开发入门,使大家对JNI开发流程有一个大致的了解,后续再进行深入学习。JNI不是Android特有的,JNI是JavaNativeInterface单词首字母的缩写,就是指用C或者C++开发的接口。... 查看详情

一步一步实现读写锁

多线程编程中,需要对共享变量进行加锁。但是频繁地加锁,会对程序效率有很大影响。在某些读多写少的场景下,多个线程进行读数据时,如果都加互斥锁,这显然是不必须的。于是读写锁便应运而生。读写锁的加锁规则:1... 查看详情

读懂源码:一步一步实现一个vue

源码阅读:究竟怎样才算是读懂了?市面上有很多源码分析的文章,就我看到的而言,基本的套路就是梳理流程,讲一讲每个模块的功能,整篇文章有一大半都是直接挂源码。我不禁怀疑,作者真的看懂了吗?为什么我看完后还... 查看详情

一步一步实现混合驱动自动化测试框架的搭建(代码片段)

一步一步实现混合驱动自动化测试框架的搭建实现功能:登录126邮箱,添加联系人,然后发送邮件,带附件 数据驱动框架结构:Action:   封装的操作元素的函数,如login,添加联系人。。。conf:日志配置文件定位... 查看详情

实现一个符合promisea+规范的promise

exportdefaultclassPromise2state=‘pending‘callbacks=[]resolve(result)this.excute(‘fulfilled‘,result,0)reject(reason)this.excute(‘rejected‘,reason,1)excute(state,data,i)if(this.state!==‘pending‘)r 查看详情

实现一个符合promisea+规范的promise

exportdefaultclassPromise2state=‘pending‘callbacks=[]resolve(result)this.excute(‘fulfilled‘,result,0)reject(reason)this.excute(‘rejected‘,reason,1)excute(state,data,i)if(this.state!==‘pending‘)r 查看详情

我是如何一步一步实现网页离线缓存的?

问题一个HybridAPP,如何做离线缓存策略?也可以简单来说,你的APP只是一个壳,里面真正加载的内容是H5,如果优化加载内容的速度?先了解一下NSURLProtocol从字面意思看它是一个协议,但是它其实是一个类,而且继承自NSObject。... 查看详情

promisea规范的一个简单的浏览器端实现

简单的实现了一个promise的规范,留着接下来模块使用。感觉还有很多能优化的地方,有时间看看源码,或者其他大神的代码主要是Then函数。回调有点绕人。1!(function(win){2345functionTask(resolver){6if(!resolver||(typeofresolver).toUpperCase()!=‘... 查看详情

vue一步一步带你封装一个按钮组件(代码片段)

#前言本文主要对子组件的封装做一个了解首先我们直接看一下代码显示首先是今天有一个学妹过来问我如何封装子组件#实现效果首先这个组件是基于eleemnt-ui进行封装的我们看一眼实现效果 有了实现效果之后我们一起来看看... 查看详情

基于promisea+规范实现一个promise(代码片段)

实现如果下规范的promiseAplus规范1,promise是一个类:有三个状态pending/等待态fulfilled/成功态rejected/失败态2,promise默认执行器立即执行3,Promise的实例都有一个then方法4,执行器中用户可以自己决定成功或者失败,并且传入成功或... 查看详情

如何一步一步用ddd设计一个电商网站——实现售价上下文

阅读目录前言明确业务细节建模实现结语 一、前言  上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/DDD_6.html,本篇我们来实现售价上下文的具体细节。 二、明确... 查看详情

用caffe一步一步实现人脸检测

...个基于caffe的人脸检测,这篇博文将告诉你怎样通过caffe一步步实现人脸检测。本文主要参考唐宇迪老师的教程,在这里感谢老师的辛勤付出。传统机器学习方法实现人脸检测:  人脸检测在opencv中已经帮我们实现了,我们要... 查看详情

一步一步实现基于gpu的pathtracer:基础

出于3D计算机图形学和图形渲染方面的个人兴趣,脑子里便萌生出了自己实现一个渲染器的想法,主要是借助pathtracing这种简单的算法,外加GPU加速来实现,同时也希望感兴趣的朋友们能够喜欢,也欢迎提出一些更好的看法~~。(... 查看详情

一步一步实现一个简单的os(简单的让boot载入setup)

这次直接写用boot载入setup模块。文件系统就先不弄了,以后再说,咱先整个转简单的载入器。我把软盘引导改成硬盘了,由于硬盘的读扇区函数简单一些。这里没有做硬盘的mbr区,我认为在如今我的这个系统里面,mbr区还不是必... 查看详情

一步一步实现基于redis的分布式锁

前提  通过多线程请求一个接口,实现抢单的实现。  总数:10  线程数:200  测试方式:Jmeter   无锁状态            在无锁状态下,实现了库存的减少的业务逻辑。测试过程中,在没有并发情... 查看详情

android一步一步带你实现recyclerview的拖拽和侧滑删除功能

先上效果图: 本篇文章我们来学习一个开源项目Android-ItemTouchHelper-Demo 这个项目使用了RecyclerView的ItemTouchHelper类实现了Item的拖动和删除功能,ItemTouchHelper是v7包下的一个类,我们看一下他的介绍Thisisautilityclasstoaddswip... 查看详情

剖析promise内部结构,一步一步实现一个完整的能通过所有testcase的promise类

本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,建议先了解Promise的使用Promise标准解读1.只有一个then方法,没有catch,race,all等方法,甚至没有构造函数Promise标准中仅指定了Promise对象的... 查看详情

vue双向绑定原理,教你一步一步实现双向绑定(代码片段)

当今前端天下以Angular、React、vue三足鼎立的局面,你不选择一个阵营基本上无法立足于前端,甚至是两个或者三个阵营都要选择,大势所趋。所以我们要时刻保持好奇心,拥抱变化,只有在不断的变化中你才能利于不败之地,保... 查看详情