一步一步实现一个Promise A+规范的 Promise

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 链式调用

原文地址:https://www.cnblogs.com/homehtml/p/11794924.html

时间: 2024-08-04 10:58:07

一步一步实现一个Promise A+规范的 Promise的相关文章

深入理解Promise并写一个符合Promise a+规范的Promise代码

关于Promise函数可以参考我写的这篇文章https://www.cnblogs.com/qiaohong/p/7705262.html,我们现在就深入理解一下这个函数. 首先说下Promise方法,Promise方法中还是有些是比较好用的,比如说Promise.all()方法(Promise.all()方法的参数是一个数组,会按照数组的结果放到成功的回调里,如果有一个错误那么就不会成功).Promise.race()方法(这个方法的参数也是一个数组,Promise.race()会同时发起并发

手写基于Promise A+规范的Promise

const PENDING = 'pending';//初始态const FULFILLED = 'fulfilled';//初始态const REJECTED = 'rejected';//初始态function Promise(executor){ let self = this;//先缓存当前promise实例 self.status = PENDING;//设置状态 //定义存放成功的回调的数组 self.onResolvedCallbacks = []; //定义存放失败回调的数组 s

教你一步一步实现一个Promise

Promise我想现在大家都非常熟悉了,主要作用就是解决异步回调问题,这里简单介绍下. Promise规范是CommonJS规范之一,而Promise规范又分了好多种,比如 Promises/A.Promises/B.Promises/Kiss等等 有兴趣的可以到这多了解一些 http://wiki.commonjs.org/wiki/Promises 现在比较流行的是Promise/A规范,人们对它的完善和扩展,逐渐形成了Promise/A+规范,A+已脱颖而出. 说到这里规范是什么,可以去这

剖析Promise内部结构,一步一步实现一个完整的、能通过所有Test case的Promise类

本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,建议先了解Promise的使用 Promise标准解读 1.只有一个then方法,没有catch,race,all等方法,甚至没有构造函数 Promise标准中仅指定了Promise对象的then方法的行为,其它一切我们常见的方法/函数都并没有指定,包括catch,race,all等常用方法,甚至也没有指定该如何构造出一个Promise对象,另外then也没有一般实现中(Q, $q等)所支持的第三个

一步一步实现基于Task的Promise库(四)无参数的WorkItem

接着上一篇我直接给出代码,现在支持了new Task(), then(), all(), any() 这些不传参的调用方式. 1 (function(){ 2 var isFunction = function (target) { 3 return target instanceof Function; 4 }; 5 var isArray = function (target) { 6 return target instanceof Array; 7 }; 8 9 //自定义事件管理(代码

一步一步实现基于Task的Promise库(三)waitFor方法的设计

在上一篇中我们已经完成了Task.js里面的all和any方法,已经可以完美的解决大部分需求,我们再来看一个需求: 我们要先读取aa.txt的内容,然后去后台解析,同时由用户指定一个文件,也要读取解析,然后当两个文件都解析完了,我们还要合并两部分内容存到cc.txt中,最后发个通知说ok了.. 这里的用户是指真正浏览网页的用户,可能是说让用户上传一个文件去读取解析,但是aa.txt是程序定好了的,我们也不希望用户上传文件之后再去读取解析aa.txt,怎么办?如果有一个waitFor方法可以等待另

一步一步实现基于Task的Promise库(一)Promise的基本实现

如果我们现在有一个需求,大概是先读取一个文件的内容,再把得到的内容传给后台去解析,最后把解析后的结果再保存到那个文件,按照最原始的做法代码就是下面这个样子的: 1 //读取文件的原始内容 2 var readFile = function(fileName, callback){ 3 window.setTimeout(function(){ 4 console.log("read '" + fileName + "' complete."); 5 var rawC

一步一步实现基于Task的Promise库(二)all和any方法的设计和实现

在上一篇中我们已经初步完成了Task类,如果仅仅是这些,那么没有多大意义,因为网上这类js库有很多,现在我们来些更复杂的使用场景. 如果我们现在有这样一个需求:我们要先读取aa.txt的内容,然后去后台解析,同时bb.txt也要读取解析,然后当两个文件都解析完了,我们还要合并两部分内容存到cc.txt中,最后发个通知说ok了..需求很变态,但是我还是想问有没有好的办法呢?按照最原始的嵌套回调的写法好像不是那么容易了,因为你没法知道aa.txt和bb.txt两个文件的读取解析谁先完成,所以你除了要

大流量网站性能优化:一步一步打造一个适合自己的BigRender插件(转)

BigRender 当一个网站越来越庞大,加载速度越来越慢的时候,开发者们不得不对其进行优化,谁愿意访问一个需要等待 10 秒,20 秒才能出现的网页呢? 常见的也是相对简单易行的一个优化方案是 图片的延迟加载.一个庞大的页面,有时我们并不会滚动去看下面的内容,这样就浪费了非首屏部分的渲染,而这些无用的渲染,不仅包括图片,还包括其他的 DOM 元素,甚至一些 js/css(某些js/css 是根据模块请求的,比如一些 ajax),理论上,每增加一个 DOM,都会增加渲染的时间.有没有办法能使得