关于Promise基本方法的简单实现

 更新时间:2022年02月07日 09:05:58   作者:编程三昧  
Promise大家一定都不陌生了,JavaScript异步流程从最初的Callback,到Promise,到Generator,再到目前使用最多的Async/Await,下面这篇文章主要给大家介绍了关于Promise基本方法的简单实现,需要的朋友可以参考下

前言

Promise 是前端面试和工作中极其常见的一个概念,关于它各种方法的手写实现也很有市场,今天在这里总结一下 Promise 基本方法的简单实现。

catch() 方法

catch 方法是对 then 方法的封装,只用于接收 reject(reason) 中的错误信息。

因为在 then 方法中 onRejected 参数是可不传的,不传的情况下,错误信息会依次往后传递,直到有 onRejected 函数接收为止,因此在写 promise 链式调用的时候, then 方法不传 onRejected 函数,只需要在最末尾加一个 catch() 就可以了,这样在该链条中的 promise 发生的错误都会被最后的 catch 捕获到。

catch(onRejected) {
	return this.then(null, onRejected);
}

done() 方法

catch 在 promise 链式调用的末尾调用,用于捕获链条中的错误信息,但是 catch 方法内部也可能出现错误,所以有些 promise 实现中增加了一个方法 done 。

done 相当于提供了一个不会出错的 catch 方法,并且不再返回一个 promise ,一般用来结束一个 promise 链。

done() {
    this.catch(reason => {
        console.log('done', reason);
        throw reason;
    });
}

finally() 方法

finally 方法用于无论是 resolve 还是 reject , finall y的参数函数都会被执行。

finally(fn) {
    return this.then(value => {
        fn();
        return value;
    }, reason => {
        fn();
        throw reason;
    });
};

Promise.all() 方法

Promise.all 方法接收一个 promise 数组,返回一个新 promise2 ,并发执行数组中的全部 promise ,所有 promise 状态都为 resolved 时, promise2 状态为 resolved 并返回全部 promise 结果,结果顺序和 promise 数组顺序一致。如果有一个 promise 为 rejected 状态,则整个 promise2 进入 rejected 状态。

static all(promiseList) {
    return new Promise((resolve, reject) => {
        const result = [];
        let i = 0;
        for (const p of promiseList) {
            p.then(value => {
                result[i] = value;
                if (result.length === promiseList.length) {
                    resolve(result);
                }
            }, reject);
            i++;
        }
    });
}

Promise.race() 方法

Promise.race 方法接收一个 promise 数组, 返回一个新 promise2 ,顺序执行数组中的 promise ,有一个 promise 状态确定, promise2 状态即确定,并且同这个 promise 的状态一致。

static race(promiseList) {
    return new Promise((resolve, reject) => {
        for (const p of promiseList) {
            p.then((value) => {
                resolve(value);
            }, reject);
        }
    });
}

Promise.resolve() 和 Promise.reject()

Promise.resolve 用来生成一个 rejected 完成态的 promise , Promise.reject 用来生成一个 rejected 失败态的 promise 。

static resolve(value) {
    let promise;

    promise = new Promise((resolve, reject) => {
        this.resolvePromise(promise, value, resolve, reject);
    });

    return promise;
}

static reject(reason) {
    return new Promise((resolve, reject) => {
        reject(reason);
    });
}

附Promise 解决过程

Promise 解决过程是一个抽象的操作,其需输入一个 promise 和一个值,我们表示为 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise 。

这种 thenable 的特性使得 Promise 的实现更具有通用性:只要其暴露出一个遵循 Promise/A+ 协议的 then 方法即可;这同时也使遵循 Promise/A+ 规范的实现可以与那些不太规范但可用的实现能良好共存。

运行 [[Resolve]](promise, x) 需遵循以下步骤:

  • x 与 promise 相等

如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise

  • x 为 Promise

如果 x 为 Promise ,则使 promise 接受 x 的状态:

- 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝
- 如果 x 处于执行态,用相同的值执行 promise
- 如果 x 处于拒绝态,用相同的据因拒绝 promise

  • x 为对象或函数

如果 x 为对象或者函数:

- 把 x.then 赋值给 then
- 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
- 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise:
    - 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
    - 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
    - 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
    - 如果调用 then 方法抛出了异常 e:
        - 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
        - 否则以 e 为据因拒绝 promise
    - 如果 then 不是函数,以 x 为参数执行 promise
- 如果 x 不为对象或者函数,以 x 为参数执行 promise

如果一个 promise 被一个循环的 thenable 链中的对象解决,而 [[Resolve]](promise, thenable) 的递归性质又使得其被再次调用,根据上述的算法将会陷入无限递归之中。算法虽不强制要求,但也鼓励施者检测这样的递归是否存在,若检测到存在则以一个可识别的 TypeError 为据因来拒绝 promise。

总结

常用的方法基本就这些, Promise 还有很多扩展方法,这里就不一一展示,基本上都是对 then 方法的进一步封装,只要你的 then 方法没有问题,其他方法就都可以依赖 then 方法实现。

到此这篇关于Promise基本方法简单实现的文章就介绍到这了,更多相关Promise基本方法实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • js 控制下拉菜单刷新的方法

    js 控制下拉菜单刷新的方法

    js 控制下拉菜单刷新的方法,需要的朋友可以参考一下
    2013-03-03
  • js中如何完美的解析数据

    js中如何完美的解析数据

    这篇文章给大家分享了JS中完美解析数据的方法和技巧,对此有兴趣的朋友可以参考学习下。
    2018-03-03
  • 动态加载图片路径 保持JavaScript控件的相对独立性

    动态加载图片路径 保持JavaScript控件的相对独立性

    根据新界面的要求,需要一部分图片来增强日期控件的美观性。考虑到既要实现加载图表的目标,又要保持控件的独立性以便将来的移植。
    2010-09-09
  • 微信小程序使用uni-app实现首页搜索框导航栏功能详解

    微信小程序使用uni-app实现首页搜索框导航栏功能详解

    这篇文章主要介绍了微信小程序使用uni-app实现首页搜索框导航栏功能,uni-app 是一个使用 Vue.js (opens new window)开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序
    2022-10-10
  • js实现图片旋转的三种方法

    js实现图片旋转的三种方法

    这篇文章主要介绍了js实现图片旋转的三种方法,需要的朋友可以参考下
    2014-04-04
  • 原生JS实现特效留言框

    原生JS实现特效留言框

    这篇文章主要为大家详细介绍了原生JS实现特效留言框,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • CascadeView级联组件实现思路详解(分离思想和单链表)

    CascadeView级联组件实现思路详解(分离思想和单链表)

    本文介绍自己最近做省市级联的类似的级联功能的实现思路,为了尽可能地做到职责分离跟表现与行为分离,这个功能拆分成了2个组件并用到了单链表来实现关键的级联逻辑,下一段有演示效果的gif图
    2016-04-04
  • JavaScript实现动态生成表格案例详解

    JavaScript实现动态生成表格案例详解

    本文主要介绍了通过JavaScript实现一个动态添加表格的案例,当点击添加按钮时,可以弹出一个表单,然后将输入的内容添加到表格中,也可以将表格中的整行内容清除。感兴趣的可以学习一下
    2021-12-12
  • JavaScript Length 属性的总结

    JavaScript Length 属性的总结

    javascript length属性是返回字符串的字符数目,length可以返回function的参数数目。接下来,通过本篇文章给大家介绍javascript length属性,对javascript length属性感兴趣的朋友可以参考下本篇文章
    2015-11-11
  • JavaScript sleep睡眠函数的使用

    JavaScript sleep睡眠函数的使用

    JavaScript是单线程运行的,没有内置的sleep函数,那么JavaScript sleep睡眠函数是怎样实现的,感兴趣的小伙伴们可以参考一下
    2021-07-07

最新评论