资讯专栏INFORMATION COLUMN

手写一款符合Promise/A+规范的Promise

rubyshen / 469人阅读

摘要:手写一款符合规范的长篇预警有点长,可以选择性观看。初始状态是,状态可以有或者不能从转换为或者从转换成即只要由状态转换为其他状态后,状态就不可变更。

手写一款符合Promise/A+规范的Promise

长篇预警!有点长,可以选择性观看。如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的。主要是代码部分有点多,不过好多都是重复的,不必担心

Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难

本篇大概分为以下步骤

实现简单的同步Promise

增加异步功能

增加链式调用then

增加catch finally方法

增加all race 等方法

实现一个promise的延迟对象defer

最终测试

实现简单的同步Promise

先大概说一下基本概念:
Promise内部维护着三种状态,即pending,resolved和rejected。初始状态是pending,状态可以有pending--->relolved,或者pending--->rejected.不能从resolve转换为rejected 或者从rejected转换成resolved.
即 只要Promise由pending状态转换为其他状态后,状态就不可变更。
ok.知道了这些后,我们开始手撸代码:

注意观看序号 1 2 3 4 5 ...


function Promise(executor){
    let that = this;
    /** 2 定义初始的一些变量 */
    that.status = "pending";
    that.value = null;
    that.reason = null;
    
    /** 3 定义初始的成功和失败函数 */
    function resolve(value){
        /** 4 判断状态是不是初始状态pending 
         *    是就转换状态 否则不转换 
         *    确保状态的变化后的不可变性 */
        if(that.status === "pending"){
            that.status = "resolved";
            that.value = value;
        }
    }
    function reject(reason){
        /** 5 同上 */
        if(that.status === "pending"){
            that.status = "rejected";
            that.reason = reason;
        }
    }
    /**
     * 1 Promise中首先传了一个executor,它是一个函数
     *   executor函数中又传了两个函数,分别是resolve和reject
     *   很显然 resolve是成功回调,reject是失败的回调
     */
    executor(resolve,reject);
}

/** 6 在Promise原型上面定义then方法
 *    then方法上面有两个回调 一个是成功后的方法 另一个是失败后的方法
 *    根据成功或失败的状态去执行相关成功onFilfulled()或者失败onRejected()的回调方法
 */
Promise.prototype.then = function(onFilfulled,onRejected){
    let that = this;
    if(that.status === "resolved"){
        /** 7 如果状态已经变更为resolved 
         *    说明resolve方法已经被调用
         *    那么此时就执行成功的回调函数onFilfulled
         *    并传入参数 that.value
         * */
        onFilfulled(that.value);
    }
    if(that.status === "rejected"){
        /** 8 同上
         *    传入参数 that.reason
         */
        onRejected(that.reason);
    }
}

module.exports = Promise;

通过require()引入手撸的Promise

let Promise = require("./myPromise");

let p1 = ()=>{
    return new Promise((resolve,reject)=>{
        resolve("success.1");
    });
}

p1().then((data)=>{
    console.log(data); // 打印 success.1
},(err)=>{
    console.log(err);
});

ok.经调用发现 此代码可以实现部分Promise的功能,但仅仅是同步下才有效果。
那异步呢? 别急这就来~:

增加异步功能

注意观看序号 1 2 3 4 5 ...


function Promise(executor){
    let that = this;
    that.status = "pending";
    that.value = null;
    that.reason = null;
    /** 1 因为异步不是立即执行 状态不会变更 成功或失败的回调函数也不会执行
     *    所以先定义好存放成功或失败回调函数的数组 
     *    以便将成功或失败的回调函数先保存起来
     * */
    that.onFilFulledCallbacks = [];
    that.onRejectedCallbacks = [];

    function resolve(value){
        if(that.status === "pending"){
            that.status = "resolved";
            that.value = value;
            /** 3 发布
             *    等待状态发生变更
             *    状态变更后 立即执行之前存放在相应数组中所有的成功或失败的回调函数
             *    即 发布
             */
            that.onFilFulledCallbacks.forEach((fn)=>{
                fn();
            });
        }
    }
    function reject(reason){
        if(that.status === "pending"){
            that.status = "rejected";
            that.reason = reason;
            /** 4 同上 */
            that.onRejectedCallbacks.forEach((fn)=>{
                fn();
            });
        }
    }
    executor(resolve,reject);
}

Promise.prototype.then = function(onFilfulled,onRejected){
    let that = this;
    if(that.status === "resolved"){
        onFilfulled(that.value);
    }
    if(that.status === "rejected"){
        onRejected(that.reason);
    }
    /** 2 订阅
     *    因为是异步 状态当时并没有立即变更 所以状态还是pending
     *    此时需要把成功或者失败的回调函数存放到对应的数组中
     *    等待状态变更时 再从数组中拿出来去执行
     *    即 订阅
     *    *存放数组时 为了执行时方便 需要把回调函数的外层包裹一层空函数
     */
    if(that.status === "pending"){
        that.onFilFulledCallbacks.push(function(){
            onFilfulled(that.value);
        });
    }
    if(that.status === "pending"){
        that.onRejectedCallbacks.push(function(){
            onRejected(that.reason);
        });
    }
}

module.exports = Promise;

代码测试:

let Promise = require("./myPromise");

let p1 = ()=>{
    return new Promise((resolve,reject)=>{
        setTimeout(function(){
            resolve("success.1");
            // reject("fail.");
        },1500);
    });
}

p1().then((data)=>{
    console.log(data); // success.1
},(err)=>{
    console.log(err);
});

可以看到 1.5s后 执行了resolve() 并打印了success.1,至此,我们实现了异步的Promise.其实这里的实现异步的思想就是发布订阅.

en~ok.高能预警

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101880.html

相关文章

  • 手写一个符合A+规范Promise

    摘要:本文同时也发布在我的博客上,欢迎之前也手写过简单的,这次则是为了通过官方的测试集,借鉴了一些下载量较多的,改了几遍,终于是通过了规范的个测试用例如何测试测试库地址在这,大家在写完自己的后,不妨也去测试一下,检验自己的是否符合规范。 本文同时也发布在我的github博客上,欢迎star~ 之前也手写过简单的promise,这次则是为了通过官方的Promise A+测试集,借鉴了一些下载量...

    jsummer 评论0 收藏0
  • promise/A+规范翻译以及手写实现

    摘要:如果实现满足所有要求,则实现可能允许。本条款允许使用特定于实现的方法来采用已知一致承诺的状态。接下来根据规范进行手写实现注释偷懒就将对应的规范标注出来,其实基本上就是对着规范实现。 如果要手写实现promise,那么先看看promise/A+规范,再来实现,将会事半功倍。那么我先翻译一下Promise/A+规范中的内容。 术语 1.1 promise 是一个带有符合此规范的the...

    LiuZh 评论0 收藏0
  • 手写一个符合promise/A+规范promise

    摘要:使用及原理分析通过关键字创建实例接受一个参数方法返回两个方法可用通过在方法中通过调用使成功或调用使失败来控制状态中可以执行同步代码也可以执行异步代码原型对象上有方法供实例调用方法接受两个参数默认为一个函数默认为一个函数当状态为时执行用户传入 promise使用及原理分析: 通过new关键字创建promise实例, 接受一个executor参数, executor方法返回两个方法 res...

    venmos 评论0 收藏0
  • 异步发展流程 —— 手写一个符合 Promise/A+ 规范 Promise

    摘要:构造函数的实现我们在使用的时候其实是使用关键字创建了一个的实例,其实是一个类,即构造函数,下面来实现构造函数。 showImg(https://segmentfault.com/img/remote/1460000018998456); 阅读原文 概述 Promise 是 js 异步编程的一种解决方案,避免了 回调地狱 给编程带来的麻烦,在 ES6 中成为了标准,这篇文章重点不是叙...

    UnixAgain 评论0 收藏0
  • JavaScript之手写Promise

    摘要:如果状态是等待态的话,就往回调函数中函数,比如如下代码就会进入等待态的逻辑以上就是简单版实现实现一个符合规范的接下来大部分代码都是根据规范去实现的。 为更好的理解, 推荐阅读Promise/A+ 规范 实现一个简易版 Promise 在完成符合 Promise/A+ 规范的代码之前,我们可以先来实现一个简易版 Promise,因为在面试中,如果你能实现出一个简易版的 Promise ...

    stefan 评论0 收藏0

发表评论

0条评论

rubyshen

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<