话不多说,直接上代码

通过ES5的模块化封装,向外暴露一个属性

(function(window){

  const PENDING = 'pending';

  const RESOLVED = 'fulfilled'

  const REJECTED = 'rejected'

  function MyPromise(excutor){

    const self = this;   //保存Promise对象,防止异步执行时,拿不到数据和方法,必要

    self.value = undefined;

    self.status = PENDING;

    self.callbacks = [] //当状态没有发生改变时,需要储存起回调函数, 在then方法中获取回调函数

    function resolve(value){

      self.value = value;

      self.status = RESOLVED;

      self.callbacks.map(cb => {

        setTimeout(() => { //定时器模拟异步执行,必须保证回调异步执行,否则顺序就乱了

           cb.onResolved(self.value)

        })

      }) //执行保存起来的成功回调函数

    }

     function reject(value){

      self.value = value;

      self.status = REJECTED ;

      self.callbacks.map(cb => {

        setTimeout(() => {

          cb.onRejected (self.value)

        })

      })//执行保存起来的失败的回调函数

    }

    try{   //若在执行器函数中主动抛出错误,需要捕获错误,并把状态更改为rejected

      excutor(resolve,reject)

    } catch (error){

      reject(error)

    }

  }

  MyPromise.prototype.then = function( onResolved,onRejected ){

    const self = this//保存当前的Promise对象

    return new Promise(resolve,reject){

      onResolved = onResolved === 'function' ? onResolved : v => v

      onRejected  = onRejected === 'function' ? onRejected :  error => {throw error}  //实现异常透传

      //判断当前的状态

      //假如Promise执行的异步任务,then方法是同步方法,那么当时Promise的状态为pending,所以不能执行回调,此时需要保存

      if(self.status === PENDING){

        // 这里只是把回调保存了起来,并没有改变当前的Promise对象,所以得进一步处理,处理和成功得处理类似

        self.callbacks.push({onResolved,onRejected})  //保存每一个then方法为一个对象,包含onResolved,onRejected两个函数

      } else if(self.status === RESOLVED){

        //1. 保证then中的回调异步执行,加一个setTimeout

        //2. 在onResolved中如果主动抛出错误,需要捕获错误

        //3. 根据Promise对象返回的结果,来决定下一个then中执行成功还是失败的回调

        //4. 如果上一个Promise返回的是一个值,如return 2,那么直接用resolve(2)执行

        //5. 如果上一个Promise返回的是一个promise对象,那么要通过promise.then 来获取promise的执行结果

        setTimeout(() => {

          try {

            const result = onResolved(self.value)

            if( result instanceof MyPromise){ //判断返回值是不是Promise对象

              //返回一个Promise对象

              result.then(

                value => {  //返回值是Promise对象,并且是成功的,那么就会执行这一个函数

                  resolve(self.value)

                }  

                error => {  //返回值是Promise对象,并且是失败的,那么就会执行这一个函数

                  rejecte(self.value)

                }

              )  

            }else {  //返回的不是一个Promise对象

               resolve(self.value)

            }

          } catch (error) {

             //与成功的处理一样,只需要更改一下回调函数,太长就不写了

          }

        })

      } else { //rejected状态}  

      }

    }

  window.MyPromise = MyPromise //向外暴露方法

})(window)

到这里就差不多写完简易的promise了,了解了原理也能更好的使用promise

欢迎指正,若有不清楚,也可评论指出

手写Promise简易版的更多相关文章

  1. 来,我们手写一个简易版的mock.js吧(模拟fetch && Ajax请求)

    预期的mock的使用方式 首先我们从使用的角度出发,思考编码过程 M1. 通过配置文件配置url和response M2. 自动检测环境为开发环境时启动Mock.js M3. mock代码能直接覆盖g ...

  2. 手写spring(简易版)

    本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作,如有错误之处忘不吝批评指正! 理解Spring本质: 相信之前在使用spring的时候大家都配置web.x ...

  3. 手写一个简易版Tomcat

    前言 Tomcat Write MyTomcat Tomcat是非常流行的Web Server,它还是一个满足Servlet规范的容器.那么想一想,Tomcat和我们的Web应用是什么关系? 从感性上 ...

  4. 我手写的简易tomcat

    前述 自己手写的简易的tomcat,实现了tomcat的基本响应功能,项目代码已经上传到我的Github,刚刚开始学习这里,当前还存在很多问题 项目简述及代码 当我们的Web运行的时候,从浏览器发出的 ...

  5. 手写Promise A+ 规范

    基于ES6语法手写promise A+ 规范,源码实现 class Promise { constructor(excutorCallBack) { this.status = 'pending'; ...

  6. 手写promise

    写在前面: 在目前的前端分开中,我们对于异步方法的使用越来越频繁,那么如果处理异步方法的返回结果,如果优雅的进行异步处理对于一个合格的前端开发者而言就显得尤为重要,其中在面试中被问道最多的就是对Pro ...

  7. 手写 Promise

    在上一章节中我们了解了 Promise 的一些易错点,在这一章节中,我们会通过手写一个符合 Promise/A+ 规范的 Promise 来深入理解它,并且手写 Promise 也是一道大厂常考题,在 ...

  8. 手写Promise看着一篇就足够了

    目录 概要 博客思路 API的特性与手写源码 构造函数 then catch Promise.resolved Promise.rejected Promise.all Promise.race 概要 ...

  9. 手写Promise中then方法返回的结果或者规律

    1. Promise中then()方法返回来的结果或者规律 我们知道 promise 的 then 方法返回来的结果值[result]是由: 它指定的回调函数的结果决定的 2.比如说下面这一段代码 l ...

随机推荐

  1. 什么是 PHP 过滤器?

    PHP 过滤器 PHP 过滤器用于验证和过滤来自非安全来源的数据,比如用户的输入. 什么是 PHP 过滤器? PHP 过滤器用于验证和过滤来自非安全来源的数据. 测试.验证和过滤用户输入或自定义数据是 ...

  2. PDOStatement::nextRowset

    PDOStatement::nextRowset — 在一个多行集语句句柄中推进到下一个行集(PHP 5 >= 5.1.0, PECL pdo >= 0.2.0)高佣联盟 www.cgew ...

  3. Prism.Interactivity 和 Prism.Modularity 介绍

    Prism.Interactivity: 主要用来截取View即界面的一些处理,而这些功能通过vm 不好实现,只能用 CommandBehaviorBase 来截取处理,特别是在处理界面异常很有用. ...

  4. 牛客挑战赛40 VMware和基站 set 二分 启发式合并 区间覆盖

    LINK:VMware和基站 一道 做法并不常见的题目 看起来很难写 其实set维护线段就可以解决了. 容易想到 第二个操作借用启发式合并可以得到一个很不错的复杂度 不过利用线段树维护这个东西 在区间 ...

  5. AC自动机&后缀自动机

    理解的不够深 故只能以此来加深理解 .我这个人就是蠢没办法 学长讲的题全程蒙蔽.可能我字符串就是菜吧,哦不我这个人就是菜吧. AC自动机的名字 AC 取自一个大牛 而自动机就比较有讲究了 不是寻常的东 ...

  6. 焦点损失函数 Focal Loss 与 GHM

    文章来自公众号[机器学习炼丹术] 1 focal loss的概述 焦点损失函数 Focal Loss(2017年何凯明大佬的论文)被提出用于密集物体检测任务. 当然,在目标检测中,可能待检测物体有10 ...

  7. Ajax 提交图片

    话不多说,直接上代码 页面部分 <form id="form1" enctype="multipart/form-data"> id_token: ...

  8. 一个C++版本的Sqlite3封装--SmartDb

    Sqlite是一个非常轻量级的开源数据库,在嵌入式系统中使用的比较多,存储管理数据非常方便,Sqlite库提供的基于C语言的API,用起来也挺简单,但是有一点不太好的就是API使用起来有些繁琐,另外就 ...

  9. 031_go语言中的通道遍历

    代码演示 package main import "fmt" func main() { queue := make(chan string, 2) queue <- &qu ...

  10. MYSQL 按某个字段分组,然后取每组前3条记录

    先初始化一些数据,表名为 test ,字段及数据为: SQL执行结果为:每个 uid  都只有 3 条记录.   SQL语句为: SELECT   * FROM   test main WHERE   ...