JavaScript实现Promise流程详解

目录
  • 构造函数
  • then 和 catch方法
  • 解决异步问题
  • all和race方法

构造函数

首先我们来看一下我们是如何使用promise的,我们在实例化对象是这么使用的:

    let p1 = new Promise((resolve, reject) => {
      let random = Math.floor(Math.random() * 10);
      if (random > 4) {
        resolve('sucess')
      } else {
        reject('erro')
      }
    })

所以我们在创建我们自己的类要考虑到如何使用这个参数。

我们来看一下, new Promise 的时候传了一个回调函数,在这个回调函数中的代码应该是被立即执行的。

而在这个回调函数中,还带有这两个参数resolve和reject(也是回调函数)。

所以在我们的构造函数中,应该是有这两个函数resolve和reject(暂时先不管这两个函数是做什么的)。

我们知道promise是有三个属性的:

pending : 待定

fulfilled : 对应resolve函数

rejected : 对应reject函数

并且状态一旦改变就不能再更改了。

所以我们的构造函数之中应该有表示当前promise状态的属性。

我们知道不管使用resolve还是reject都会传入一个res变量,作为结果值,所以我们在用一个属性来保存resolve和reject的结果值。

最后我们可以设计出这样的构造函数:

function Mypromise (config) {
  this.status = 'pending';
  this.res = ''
  let resolve = (data) => {
    this.status = 'fulfilled';
    this.res = data
  }
  let reject = (data) => {
    this.status = 'rejected';
    this.res = data
  }
  config(resolve, reject)
}

then 和 catch方法

我们先来回顾一哈怎么使用这两个方法:

    p1
      .then(res => {
        console.log(res);
      })
      .then(res => {
        console.log(res);
      })
      .catch(err => {
        console.log(err);
      })

上面的代码我们可以看到,then和catch方法,都接受了一个回调函数

而这个回调函数的参数也就是我们之前定义的this.res。

所以我们可以想到这么做:

Mypromise.prototype.then = function (config) {
  if (this.status == 'fulfilled') {
    config(this.res)
  }
}
Mypromise.prototype.catch = function (config) {
  if (this.status == 'rejected') {
    config(this.res)
  }
}

但是这种方法不能实现链式调用,就是不能连着使用then方法。

但是如果我想实现出这个模式,我们应该在then方法下回一个对象,而这个对象正常来讲就是this。

所以我们可以直接返回this吗,看下面这个情况。

p1
  .then(res => {
    console.log(res);
    return new Promise((resolve, reject) => {
      resolve('1111')
    })
  })
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.log(err);
  })

在then方法下如果返回了一个新的promise的话,我们就不能直接在then方法里面直接返回this了。

所以我们应该先判断then的回调函数是否返回了新的对象,如果没有才返回当前then的this对象。

Mypromise.prototype.then = function (config) {
  if (this.status == 'fulfilled') {
    var res = config(this.res)
  }
  return res || this;
}
Mypromise.prototype.catch = function (config) {
  if (this.status == 'rejected') {
    var res = config(this.res)
  }
  return res || this;
}

解决异步问题

上面的代码,似乎看着没有什么问题了,但是如果我这么写的话:

    let p2 = new Mypromise((resolve, reject) => {
      setTimeout(() => {
        reject('p2 resolve')
      }, 1000);
    })

问题就大大的出来了,为什么呢? 因为我在p2.then的时候,定时器没有跑完,所以p2的状态现在还是pending,根本不会走下去。

这里面我们用一种经典的解决模式,在我写之前的axios和路由也经常可以看到。

在then方法中,如果当前状态为pending(这句话很重要o),我们就把当前的回调函数保存下来(不一定是一个,有可能是多个then,所以我们采用数组保存)。

那我们保存起来什么时候用呢?当然是在定时器结束后用!那定时器什么时候结束呢?当然是当前promise状态改变的时候,所以,我们在resolve和reject方法之中,要将这些方法进行调用!!!

所以我们要修改构造函数:

function Mypromise (config) {
  this.status = 'pending';
  this.res = '';
  this.saveResolve = [];
  this.saveReject = [];
  let resolve = (data) => {
    if (this.status == 'pending') {
      this.status = 'fulfilled';
      this.res = data
      this.saveResolve.forEach(val => {
        val(this.res)
      })
    }
  }
  let reject = (data) => {
    if (this.status == 'pending') {
      this.status = 'rejected';
      this.res = data
      this.saveReject.forEach(val => {
        val(this.res)
      })
    }
  }
  config(resolve, reject);
}

然后再修改我们的then和catch方法:

Mypromise.prototype.then = function (config) {
  if (this.status == 'pending') {
    this.saveResolve.push(config);
  }
  if (this.status == 'fulfilled') {
    var res = config(this.res)
  }
  return res || this;
}
Mypromise.prototype.catch = function (config) {
  if (this.status == 'pending') {
    this.saveReject.push(config)
  }
  if (this.status == 'rejected') {
    var res = config(this.res)
  }
  return res || this;
}

这样关于异步的问题我们就解决了。

all和race方法

还是老样子,在写之前我们先回顾一下是怎么用的:

    Mypromise.all([p2, p3, p4])
      .then(res => {
        console.log(res);
      })
      .catch(err => {
        console.log(err);
      })
    Mypromise.race([p2, p3, p4])
      .then(res => {
        console.log(res);
      })
      .catch(err => {
        console.log(err);
      })

那我们知道,二者都死以一个数组作为参数,这里面我门就不考虑其他的情况了,我就当数组里面全是promise对象了。。。

二者的区别在于:

all:当所有的promise都执行完,并且状态都为fulfilled,all方法返回的promise为fulfilled,否则为rejected。

race:第一个出现结果的promise对象就是race放回的promise的结果。

现在我们来想一下all方法如何来实现,我们拿到了数组参数之后,一定是要遍历一遍的。

然后对于每一个元素都调用then方法和catch方法。

then方法要有一个结果数组保存每个promise的结果值。

我们可以用一个计数器来计算then方法的调用次数,如果计数器的大小等于数组长度,那么就证明所有的promise全部都是fulfilled,可以返回结果数组。

catch方法只要是被调用了一次,那么直接返回结果,不多bb,直接返回

最后记住要把新的promise返回o。

Mypromise.all = function (arr) {
  let result = [];
  let count = 0;
  let promise = new Mypromise((resolve, reject) => {
    for (var i = 0; i < arr.length; i++) {
      arr[i]
        .then(res => {
          result.push(res);
          count++;
          if (count == arr.length) resolve(result);
        })
        .catch(err => {
          reject(err)
        })
    }
  })
  return promise
}

race的方法的话,实现起来可能就更简单了,不管那个promise的then方法还是catch方法触发了,直接返回结果:

Mypromise.race = function (arr) {
  let promise = new Mypromise((resolve, reject) => {
    for (var i = 0; i < arr.length; i++) {
      arr[i]
        .then(res => {
          resolve(res);
        })
        .catch(err => {
          reject(err)
        })
    }
  })
  return promise
}

到此这篇关于JavaScript实现Promise流程详解的文章就介绍到这了,更多相关JS Promise内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JavaScript实现一个Promise队列小工具

    目录 摘要 思考 实现 总结 摘要 在百度的解释中,队列是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表.进行插入操作的端称为队尾,进行删除操作的端称为队头. 受这个队列结构的启发,在前端不同的业务场景中,由于一次性发起的异步请求过多,并且这些服务位于不同组件或者不同兄弟功能之间,我们无法直接对这些方法进行同步,所以需要引入队列的概念,对这些并发性的问题进行顺序处理. 思考 为什么要写一个类似于队列的功能? 我们知道

  • JavaScript详解使用Promise处理回调地狱与async await修饰符

    目录 Promise 回调地狱 Promise简介 Promise简单使用 async和await 修饰符 小结 Promise Promise能够处理异步程序. 回调地狱 JS中或node中,都大量的使用了回调函数进行异步操作,而异步操作什么时候返回结果是不可控的,如果我们希望几个异步请求按照顺序来执行,那么就需要将这些异步操作嵌套起来,嵌套的层数特别多,就会形成回调地狱 或者叫做 横向金字塔. 案例:有a.txt.b.txt.c.txt三个文件,使用fs模板按照顺序来读取里面的内容,代码:

  • 万字详解JavaScript手写一个Promise

    目录 前言 Promise核心原理实现 Promise的使用分析 MyPromise的实现 在Promise中加入异步操作 实现then方法的多次调用 实现then的链式调用 then方法链式调用识别Promise对象自返回 捕获错误及 then 链式调用其他状态代码补充 捕获执行器错误 捕获then中的报错 错误与异步状态的链式调用 将then方法的参数变成可选参数 Promise.all方法的实现 Promise.resolve方法的实现 finally方法的实现 catch方法的实现 完整

  • JavaScript Promise执行流程深刻理解

    目录 手撕Promise 看完收获 Promise分析 作用 特点 总体实现 resolve和reject初步实现 then方法的实现 Promise.all的实现 手撕Promise 手写一个Promise已经是一个常见的手写功能了,虽然实际工作上可能并不会用到.但是在面试时还是会经常被提起的. 看完收获 实现一个手写promise 对promise执行流程有着更深刻的理解 从底层理解proimse,应对各种面试题 Promise分析 作用 通过链式调用的方式,解决回调地狱的问题. 特点 是E

  • 使用 JavaScript Promise 读取 Github 用户数据

    代码如下: // Make a request for user.json fetch('/article/promise-chaining/user.json') // Load it as json .then(response => response.json()) // Make a request to GitHub .then(user => fetch(`https://api.github.com/users/${user.name}`)) // Load the respon

  • JavaScript中 Promise 的使用技巧

    “生产代码”是可能需要一些时间来执行的代码. “消费代码”是必须等待结果的代码. Promise 是一个 JavaScript 对象,它链接生产代码和消费代码. 看一段最简单的代码: let myPromise = new Promise(function(myResolve, myReject) { // "Producing Code" (May take some time) myResolve(); // when successful myReject(); // when

  • 深入学习JavaScript中的promise

    目录 为什么要用Promise? 使用Promise解决异步控制问题 Promise的结构 回调函数 为什么异步代码一定是回调函数结构? 刨析Promise 原型方法——catch\finally\then 为什么要在.then的回调函数中return一个Promise呢? 那如果我们不指明return返回值,它会返回什么呢?是如何实现链式调用呢? resolve和reject resolve() reject() Promise常用API——all().allSettled().any().r

  • javascript中的糖衣语法Promise对象详解

    目录 一.Promise的诞生 1.回调地狱 二.Promise的行为 1.Promise的语法 2.Promise的方法 (1)Promise.prototype.then() (2)Promise.prototype.catch() (3)Promise.prototype.finally() (4)Promise.resolve() (5)Promise.reject() (6)Promise.all() (7)Promise.race() 三.Promise的场景 1.Ajax请求 2.

  • JavaScript实现Promise流程详解

    目录 构造函数 then 和 catch方法 解决异步问题 all和race方法 构造函数 首先我们来看一下我们是如何使用promise的,我们在实例化对象是这么使用的: let p1 = new Promise((resolve, reject) => { let random = Math.floor(Math.random() * 10); if (random > 4) { resolve('sucess') } else { reject('erro') } }) 所以我们在创建我们

  • javascript中Promise使用详解

    目录 一.首先,要知道为什么要用Promise语法? 二.接着,来了解一下回调地狱(Callback Hell) 三.最后,也是本章的重头戏,Promise的基本使用 (一) resolve函数 (二) rejected函数 (三)Promise的API 1. then 2. catch 3. finally 4. Promise.all 5. Promise.race 四.最后 前言: 做过前端开发的都知道,JavaScript是单线程语言,浏览器只分配给JS一个主线程,用来执行任务,但是每次

  • JavaScript制作楼层导航效果流程详解

    目录 本期目标 1. 功能实现 1.1 结构层 1.2 样式层 1.3 行为层 1.3.1 楼层跳转 1.3.2 楼层监听 2. 效果预览 3. 项目代码 本期目标 使用JavaScript制作楼层导航效果,实现两个功能: 楼层跳转 楼层监听 1. 功能实现 1.1 结构层 <div id="box" class="box"> <ul class="list"> <li class="content-par

  • javascript实现计算器功能详解流程

    目录 1.计算器功能介绍 2.计算器页面设计 1.导航栏部分 2.数据部分 3.index.wxml布局页面 4.index.css样式页面 5.运行结果 3.功能实现部分 1.删除功能 2.清空功能 3.其他功能实现 1.计算器功能介绍 可以实现数据的加(+),减(-),乘(*),除(/),取余运算(%),以及实现数据的删除(Del)和清空功能(C). 2.计算器页面设计 1.导航栏部分 { "navigationBarBackgroundColor": "#fff&quo

  • 如何从零开始利用js手写一个Promise库详解

    前言 ECMAScript 是 JavaScript 语言的国际标准,JavaScript 是 ECMAScript 的实现.ES6 的目标,是使得 JavaScript 语言可以用来编写大型的复杂的应用程序,成为企业级开发语言. 概念 ES6 原生提供了 Promise 对象. 所谓 Promise,就是一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理. 三道思考题 刚开始写前端的时候,处理异步请求经常用

  • Angularjs Promise实例详解

    一.什么是Promise Promise是对象,代表了一个函数最终可能的返回值或抛出的异常,就是用来异步处理值的. Promise是一个构造函数,自己身上有all.reject.resolve这几个异步方式处理值的方法,原型上有then.catch等同样很眼熟的方法. 二.为什么使用Promise 有了Promise对象,就可以把异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数.此外,Promise对象提供了统一的接口,使得控制异步操作更加容易. Promise对象有以下2个特点: 1

  • ES6学习教程之Promise用法详解

    前言 promise用了这么多年了,一直也没有系统整理过.今天整理整理promise的相关东西,感兴趣的可以一起看一看.我尽量用更容易理解的语言来剖析一下promise 我准备分两篇文章来说明一下promise 一篇来理解和使用promise(本篇) 另一篇来从promise使用功能的角度来剖析下promise的源码(下一篇) 1.什么是Promise 我的理解是:实现让我们用同步的方式去写异步代码的一种技术.是异步解决方案的一种. 他可以将多个异步操作进行队列化,让它们可以按照我们的想法去顺序

  • JavaScript DOMContentLoaded事件案例详解

    DOMContentLoaded 事件 字面上看,它会在dom加载完成后触发. 与window.onload事件非常相似,但有一定区别: DOMContentLoaded 事件是在文档完全加载和解析之后触发: window.onload 事件不但文档完全加载和解析完毕,相关资源都要加载完毕,比如图片和CSS文件等: 下一个问题是什么时候dom加载完毕,这得从浏览器渲染说起,浏览器显示网页的过程可以做如下描述: 1.   请求得到html文档,根据文档请求更多的img,css及其它资源文件: 2.

  • 微信小程序访问mysql数据库流程详解

    目录 1 开通云上的mysql 2 创建自定义连接器 3 创建云函数 4 安装依赖 5 出参映射 6 在小程序中使用连接器 总结 1 开通云上的mysql 经过询价,我发现阿里云的数据库是比较便宜的,新人购买非常划算.对于爱学习的博主来说,果断购买一个. 按照操作指引购买后,云会帮你创建一系列的环境,在控制台就可以看到属于自己的实例 点击操作列上的管理,就可以创建我们自己的数据库.配置的步骤是先创建数据库的账号 然后创建一个数据库 都设置好之后就可以登录数据库,创建表,加数据了 刚创建好的数据库

随机推荐