美文网首页
ES6 实现自己的 Promise

ES6 实现自己的 Promise

作者: you的日常 | 来源:发表于2022-02-15 14:58 被阅读0次

一、JavaScript 异步编程背景

从去年 ES2015 发布至今,已经过去了很久,ES2015 发布的新的语言特性中最为流行的也就莫过于 Promise 了,Promise 使得如今 JavaScript 异步编程如此轻松惬意,甚至慢慢遗忘了曾经那不堪回首的痛楚。

其实从 JavaScript 诞生,JavaScript 中的异步编程就已经出现,例如点击鼠标、敲击键盘这些事件的处理函数都是异步的,时间到了 2009 年,Node.js 横空出世,在整个 Node.js 的实现中,将回调模式的异步编程机制发挥的淋漓尽致,Node 的流行也是的越来越多的 JavaScripter 开始了异步编程,但是回调模式的副作用也慢慢展现在人们眼前,错误处理不够优雅以及嵌套回调带来的“回调地狱”。

这些副作用使得人们从回调模式的温柔乡中慢慢清醒过来,开始寻找更为优雅的异步编程模式,路漫漫其修远兮、吾将上下而求索。时间到了 2015 年,Promise 拯救那些苦苦探索的先驱。行使它历史使命的时代似乎已经到来。

每个事物的诞生有他的历史使命,更有其历史成因,促进其被那些探索的先驱们所发现。
了解 nodejs 或者熟悉浏览器的人都知道,JavaScript 引擎是基于事件循环或单线程这两个特性的。更为甚者在浏览器中,更新 UI(也就是浏览器重绘、重拍页面布局)和执行 JavaScript 代码也在一个单线程中,可想而知,一个线程就相当于只有一条马路,如果一辆马车抛锚在路上了阻塞了马路,那么别的马车也就拥堵在了那儿,这个单线程容易被阻塞是一个道理,单线程也只能允许某一时间点只能够执行一段代码。
同时,JavaScript 没有想它的哥哥姐姐们那么财大气粗,像 Java 或者 C++,一个线程不够,那么再加一个线程,这样就能够同时执行多段代码了,但是这样就会带来的隐患就是状态不容易维护,JavaScript 选择了单线程非阻塞式的方式,也就是异步编程的方式,就像上面的马车抛锚在了路上,那么把马车推到路边的维修站,让其他马车先过去,等马车修好了再回到马路上继续行驶,这就是单线程非阻塞方式。正如 Promise 的工作方式一样,通过 Promise 去向服务器发起一个请求,毕竟请求有网络开销,不可能马上就返回请求结果的,这个时候 Promise 就处于 pending 状态,但是其并不会阻塞其他代码的执行,当请求返回时,修改 Promise 状态为 fulfilled 或者 rejected(失败请求)。同时执行绑定到这两个状态上面的“处理函数”。这就是异步编程的模式,也就是 Promise 兢兢业业的工作方式,在下面一个部分将详细讨论 Promise。

二、Promise 基础

怎么一句话解释 Promise 呢?Promise 可以代指那些尚未完成的一些操作,但是其在未来的某个时间会返回某一特定的结果。

当创建一个 Promise 实例后,其代表一个未知的值,在将来的某个时间会返回一个成功的返回值,或者失败的返回值,我们可以为这些返回值添加处理函数,当值返回时,处理函数被调用。Promise 总是处于下面三种状态之一:

  • pending: Promise 的初始状态,也就是未被 fulfilled 或者 rejected 的状态。
  • fulfilled: 意味着 promise 代指的操作已经成功完成。
  • rejected:意味着 promise 代指的操作由于某些原因失败。

一个处于 pending 状态的 promise 可能由于某个成功返回值而发展为 fulfilled 状态,也有可能因为某些错误而进入 rejected 状态,无论是进入 fulfilled 状态或者 rejected 状态,绑定到这两种状态上面的处理函数就会被执行。并且进入 fulfilled 或者 rejected 状态也就不能再返回 pending 状态了。

三、边学边写

上面说了那么多,其实都是铺垫。接下来我们就开始实现自己的 Promise 对象。go go go!!!

第一步:Promise 构造函数

Promise 有三种状态,pending、fulfilled、rejected。

const PENDING = 'PENDING' // Promise 的 初始状态
const FULFILLED = 'FULFILLED' // Promise 成功返回后的状态
const REJECTED = 'REJECTED' // Promise 失败后的状态

有了三种状态后,那么我们怎么创建一个 Promise 实例呢?

const promise = new Promise(executor) // 创建 Promise 的语法

通过上面生成 promise 语法我们知道,Promise 实例是调用 Promise 构造函数通过 new 操作符生成的。这个构造函数我们可以先这样写:

class Promise {
    constructor(executor) {
        this.status = PENDING // 创建一个 promise 时,首先进行状态初始化。pending
        this.result = undefined // result 属性用来缓存 promise 的返回结果,可以是成功的返回结果,或失败的返回结果
        }
}

我们可以看到上面构造函数接受的参数 executor。它是一个函数,并且接受其他两个函数(resolve 和 reject)作为参数,当 resolve 函数调用后,promise 的状态转化为 fulfilled,并且执行成功返回的处理函数(不用着急后面会说到怎么添加处理函数)。当 reject 函数调用后,promise 状态转化为 rejected,并且执行失败返回的处理函数。

现在我们的代码大概是这样的:

class Promise {
constructor(executor) {
    this.status = PENDING
    this.result = undefined
    executor(data => resolveProvider(this, data), err => rejectProvider(this, err))
    }
}


function resolveProvider(promise, data) {
    if (promise.status !== PENDING) return false
    promise.status = FULFILLED
}

function rejectProvider(promise, data) {
    if (promise.status !== PENDING) return false
    promise.status = FULFILLED
}

Dont Repeat Yourselt!!!我们可以看到上面代码后面两个函数基本相同,其实我们可以把它整合成一个函数,在结合高阶函数的使用。

const statusProvider = (promise, status) => data => {
    if (promise.status !== PENDING) return false
    promise.status = status
    promise.result = data
}

class Promise {
    constructor(executor) {
        this.status = PENDING
        this.result = undefined
        executor(statusProvider(this, FULFILLED), statusProvider(this, REJECTED))
        }
}

现在我们的代码就看上去简洁多了。

第二步:为 Promise 添加处理函数

其实通过 new Promise(executor)已经可以生成一个 Promise 实例了,甚至我们可以通过传递到 executor 中的 resolve 和 reject 方法来改变 promise 状态,但是!现在的 promise 依然没啥卵用!!!因为我们并没有给它添加成功和失败返回的处理函数。

首先我们需要给我们的 promise 增加两个属性,successListener 和 failureListener 用来分别缓存成功处理函数和失败处理函数。

class Promise {
    constructor(executor) {
        this.status = PENDING
        this.successListener = []
        this.failureListener = []
        this.result = undefined
        executor(statusProvider(this, FULFILLED), statusProvider(this, REJECTED))
        }
}

怎么添加处理函数呢?ECMASCRIPT 标准中说到,我们可以通过 promise 原型上面的 then 方法为 promise 添加成功处理函数和失败处理函数,可以通过 catch 方法为 promise 添加失败处理函数。

相关文章

  • 实现 Promise/A+ 规范 & ES6 Promise方法

    实现 Promise/A+ 规范 检测通过 实现 ES6 Promise 方法

  • js sleep

    // promise 在ES6的语法中,Promise是sleep方法异步的实现一种方式,借助Promise方法可...

  • JavaScript 再学习:Promise的含义

    Promise 的含义 Promise 在 JavaScript 语言早有实现,ES6 将其写进了语言标准,统一了...

  • VUE多个方法执行完回调

    用Promise.all来实现。Promise是ES6的新特性,用于处理异步操作逻辑,用过给Promise添加th...

  • 前端知识总结——ES6重难点

    Promise实现 promise是ES6新增的语法,解决回调地狱问题 可以把 Promise 看成一个状态机,它...

  • Promise 对象

    一、Promise的含义 Promise在JavaScript语言中早有实现,ES6将其写进了语言标准,统一了用法...

  • Promise的简单实现

    随着ES6的出现,Promise成为标准,平时使用的次数也增加。但是Promise的原理是什么,如何实现链式调用。...

  • ES6 实现自己的 Promise

    一、JavaScript 异步编程背景 从去年 ES2015 发布至今,已经过去了很久,ES2015 发布的新的语...

  • 来,用ES6写个Promise吧

    本文采用es6语法实现Promise基本的功能, 适合有javascript和es6基础的读者,如果没有,请阅读 ...

  • Promise的简单实现

    es6版本的 es5版本 promise 友情提醒 promise还有很多特征 这里的实现还缺很多特征

网友评论

      本文标题:ES6 实现自己的 Promise

      本文链接:https://www.haomeiwen.com/subject/avgzgctx.html