Promise 是一种流行的异步解决方案,它支持异步操作,并且可以对异步操作的结果进行处理。它的设计目标是为了解决 JavaScript 中异步编程的问题,使异步编程变得更加简单和有序。在 ES6 中,Promise 已经成为了内置对象,成为了一个重要的 JS 标准库。
Promise 的基本概念
Promise 的设计是基于两个基本概念的:Promise 对象和状态。
Promise 对象
在 ES6 中,Promise 对象是一个代理对象,代表一个异步操作的最终完成(或失败)及其结果值的表示。一个 Promise 对象最初是等待中(pending)的,此时它表示还没有得到任何值,但是可能在未来某一时刻会变为完成(fulfilled)或拒绝(rejected)状态。
状态
Promise 对象最初是等待中状态(pending),当它变成完成状态(fulfilled)时,代表异步操作成功完成,并返回一个可用的结果值。而当它变成拒绝状态(rejected)时,代表异步操作失败,返回一个错误信息或异常对象。
Promise 的特点
Promise 有以下几个特点:
- Promise 对象是代理对象,它将异步操作的结果通知给 Promise 的使用者。
- Promise 对象是不可变的。它一旦变为完成状态或者拒绝状态,就不会再改变它的状态了。
- Promise 对象支持链式操作,可以一直链式调用多个 Promise 对象,来制定一系列异步操作的顺序和依赖关系。
- Promise 对象有统一的错误处理机制,可以使用 catch() 方法来捕获异步操作返回的错误信息。
Promise 的实现原理
实现一个 Promise 对象,我们需要先从它的构造函数入手。Promise 的构造函数如下:
----- ------- - --------------------- - -- --- - -
这里的 executor 是一个函数,它将作为 Promise 对象构造函数的参数,当 Promise 实例化时会立即被执行。executor 接收两个函数作为参数:resolve 和 reject。resolve 和 reject 函数将 Promise 变成完成或拒绝状态,它们对 Promise 对象的状态和结果值进行了处理。
----- ------- - --------------------- - ----------- - ---------- -- ------- ------------ ----------- - ----- -- ------- ---- ------------------- - ----- -- -- ------- - ------ -- ------------------- - ----- -- -- ------- - ------ ------ ------------- - --- -- --------- ------ ----------- --- - ---------------------------------- ------------------------- - ----- ----- - ------------------ - - --------------- - -- ------------ --- ---------- - ----------- - ------------ ----------- - ------ ----------------------------------------------- ------------- - ----- - - -------------- - -- ------------ --- ---------- - ----------- - ----------- ----------- - ------ ----------------------------------------------- ------------- - ----- - - -
在上面的代码中,我们定义了私有变量 _state、_value、_deferredState、_deferredValue 和 _handler。其中,_state 存储 Promise 对象的状态,默认为等待中状态;_value 存储 Promise 的结果值;_deferredState 和 _deferredValue 保存 resolve 和 reject 函数;_handler 用来存储我们后面会讲到的 then() 方法指定的各种回调函数。
Promise 对象主要有三种状态:等待中状态(pending)、完成状态(fulfilled)和 拒绝状态(rejected)。当 Promise 变为完成或拒绝状态后,它就不会再改变它的状态了。
_resolve() 方法用于将 Promise 变成完成状态。它将传入的 value 参数存储到 _value 变量中,修改 _state 变量的值,并且遍历存储在 _handler 数组中的回调函数,并执行它们。
_reject() 方法用于将 Promise 变成拒绝状态。它将传入的 error 参数存储到 _value 变量中,修改 _state 变量的值,并且遍历存储在 _handler 数组中的回调函数,并执行它们。
注意,当 Promise 对象的状态发生变化时,它的处理程序函数是异步执行的。这是因为在此之前,它们是存储在 _handler 数组中的。当时延续 resolve 或 reject 调用时,以及传递给 setTimeout() 等计时器函数的回调函数时,函数的执行是异步的。
现在我们已经实现了 Promise 对象的基本构造函数,下面来实现 then() 方法。
----- ------- - --------------------- - -- --- - ----------------- ----------- - --- ------- - --- ---------- -- ---- -------------------- ------------ ----- -- - --- - -- ------- ----------- --- ----------- - ----- ------------- - ----------------- -- -------------- -- ------ ------------------ --- ----------- - ------------- ------------- -- - ------------------------ -- -------------- -- - ----------------------- --- - ---- - -------------------------------- - - ---- - ---------------------- - - ----- --- - ------------------- - -- ----------- ----- -- - --- - -- ------- ---------- --- ----------- - ----- ------------- - ---------------- -- -------------- -- ------ ------------------ --- ----------- - ------------- ------------- -- - ------------------------ -- -------------- -- - ----------------------- --- - ---- - -------------------------------- - - ---- - --------------------- - - ----- --- - ------------------- - -- --- -- ------------ --- ------------ - ------------- -- - ------------------------------------ -- --- - ---- -- ------------ --- ----------- - ------------- -- - ------------------------------------ -- --- - ------ -------- - -
Promise 的 then() 方法接受两个参数:onFulfilled(Promise 变成成功状态时调用)和 onRejected(Promise 变成失败状态时调用)。当 Promise 对象成功时,它将调用 onFulfilled 方法,并将结果传递给它。当 Promise 对象失败时,它将调用 onRejected 方法,并将异常对象传递给它。
在 then() 方法中,我们创建一个新的 Promise 对象,然后将需要执行的 onfulfilled 和 onRejected 函数保存到 _handler 数组中。在 Promise 变成完成或拒绝状态时,我们将遍历 _handler 数组,并执行保存的函数。
注意一点,Promise 对象的处理程序函数都是异步执行的。我们在代码中使用了 setTimeout() 以保证异步执行。
实际上,在完成和拒绝时始终有一个异步调用的任务在处理,以确保任何传递给 then() 方法的处理程序都将在处理程序添加到处理程序数组中之前调用。这就是为什么我们需要在切换状态之前使用 setTimeout()。
Promise 的示例代码
下面提供一个使用 Promise 的简单示例,将对一个 json 文件进行 fetch。
---------------------- ------------ -- - ------------------ -- -------------- -- - --------------- ----- ------------ ------------------- --- -------- -------------- - ------ --- ----------------- ------- -- - ---------- ---------------- -- - -- ------------- - ------ ---------------- - ----- --- -------------- -------- --- --- ------ -- ------------ -- - -------------- -- -------------- -- - -------------- --- --- -
在上面的代码中,我们定义了一个 fetchData 函数,它接收一个 URL 参数,并返回一个 Promise 对象。如果返回的 response 状态码为 ok(即 200 到 299 范围内的状态码),它会返回 JSON 格式的 response 数据,否则会抛出一个错误。
在 then() 方法中,我们将调用 resolve() 函数,并将返回的 data 对象传递给它。
在 catch() 方法中,我们将调用 reject() 函数,并将错误对象传递给它。在此处我们可以编写错误处理代码。
在主函数中,我们调用 fetchData() 函数,并在 then() 方法中打印响应数据,而在 catch() 方法中打印错误信息。
结论
ES6 中内置的 Promise 对象,提供了一种简单的解决方案,可以优雅地处理异步编程问题。在实现 Promise 的时候,我们需要了解 Promise 对象的基本概念和特点,以及它的实现原理,才能更好地理解 Promise 对象的使用和扩展。为了更好地理解 Promise 对象,我们通过示例代码演示了 Promise 的基本使用方法。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/66ff7efe1b0bf82c71cab926