独家配方 - Promise 使用小技巧

简介: 虽然现在前端开发中大部分的异步代码中的回调都在慢慢的被 Promise 所取代,然而大部分的原生 API 和一些库都还只有回调的调用方式。于是很多时候我们需要将一些库、原生 API 转换成 Promise,此时不可避免的就是写一个 Promise 将其包裹

网络异常,图片无法展示
|

虽然现在前端开发中大部分的异步代码中的回调都在慢慢的被 Promise 所取代,然而大部分的原生 API 和一些库都还只有回调的调用方式。于是很多时候我们需要将一些库、原生 API 转换成 Promise,此时不可避免的就是写一个 Promise 将其包裹:

const readFile = file => {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.readAsString(file);
        reader.addEventListener('load', e => {
            resolve(e.result);
        });
        reader.addEventListener('error', e => {
            reject(e);
        });
    });
};
复制代码

然而,在 n 年前的一天,我突然看这段代码不顺眼,好不容易拜托了回调地狱,又来了一层 Promise,我表示很难受,于是我将它改成了这样:

const readFile = file => {
    let resolve, reject;
    const promise = new Promise((_resolve, _reject) => {
        resolve = _resolve;
        reject = _reject;
    });
    const reader = new FileReader();
    reader.readAsString(file);
    reader.addEventListener('load', e => {
        resolve(e.result);
    });
    reader.addEventListener('error', e => {
        reject(e);
    });
    return promise;
};
复制代码

乍看之下,为了节省一个层级缩进,增加了 n 行代码,不过别着急,这里还有优化的空间:

const controllerFactory = () => {
    let resolve, reject;
    const promise = new Promise((_resolve, _reject) => {
        resolve = _resolve;
        reject = _reject;
    });
    return [promise, resolve, reject];
};
const readFile = file => {
    const [controller, success, error] = controllerFactory();
    const reader = new FileReader();
    reader.readAsString(file);
    reader.addEventListener('load', e => {
        success(e.result);
    });
    reader.addEventListener('error', e => {
        error(e);
    });
    return controller;
};
复制代码

这样将 Promise 的实例化部分的代码抽离出来,我们就得到一个比较干净的 readFile 了,看起来舒服多了 😌。

这样的写法好处就是,当你有个超大的方法需要转换为 Promise 写时,不用再跑到方法头尾加上 Promise 包裹,直接在将实参里的 successerror 去掉,添加 factory 代码并返回即可:

源代码:

const myFunc = (success, error) => {
    // ...
    // a lot of code
    if (e) {
        error(e);
    } else {
        success(result);
    }
};
复制代码

Promise 改造后:

const myFunc = () => {
    return new Promise((resolve, reject) => {
        // ...
        // a lot of code
        if (e) {
            reject(e);
        } else {
            resolve(result);
        }
    });
};
复制代码

或是需要判断包裹区域进行包裹:

const myFunc = () => {
    // ...
    // a lot of code
    return new Promise((resolve, reject) => {
        if (e) {
            reject(e);
        } else {
            resolve(result);
        }
    });
};
复制代码

而使用 controllerFactory 改造后:

const myFunc = () => {
    const [controller, success, error] = controllerFactory();
    // ...
    // a lot of code
    if (e) {
        error(e);
    } else {
        success(result);
    }
    return controller;
};
复制代码

个人感觉这样代码看起来更舒适,当然,这种写法是好是坏见仁见智,欢迎指点讨论。

相关文章
|
数据可视化 数据挖掘
【因果推断】Day01- 实用计量方法图解与概述
【因果推断】Day01- 实用计量方法图解与概述
461 2
|
机器学习/深度学习 Dart TensorFlow
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(5)
TensorFlow Lite,ML Kit 和 Flutter 移动深度学习:6~11(5)
338 0
|
11月前
|
网络协议 网络架构
OSPF中的ASBR-Summary LSA详解
OSPF中的ASBR-Summary LSA详解
482 4
|
12月前
|
机器学习/深度学习 人工智能 自然语言处理
人工智能技术及其应用:未来的发展趋势
【10月更文挑战第16天】人工智能技术及其应用:未来的发展趋势
|
12月前
|
编译器 C语言
C语言预处理详解
C语言预处理详解
|
10月前
|
消息中间件 安全 Java
vulhub部分复现记录(后面大概都是原文档了,也比较难复现就不继续了)
本文介绍了多个软件的安全漏洞及其复现过程,涉及的软件包括Vulhub、Flask、ActiveMQ、Adminer、Airflow、Apache Druid、Apereo CAS、APISIX、AppWeb、Aria2、Bash、Cacti、Celery、CGI、ColdFusion和Confluence。每个部分详细描述了漏洞的背景、环境搭建步骤、漏洞复现的具体操作和验证方法。例如,Flask的SSTI漏洞通过构造特定的模板参数实现命令执行;ActiveMQ的反序列化漏洞利用特制的序列化对象触发;这些示例不仅展示了漏洞的危害性,还提供了实际的复现步骤,帮助读者深入理解这些安全问题。
1662 3
vulhub部分复现记录(后面大概都是原文档了,也比较难复现就不继续了)
|
开发框架 安全 .NET
记一次绕过安全狗和360提权案例
记一次绕过安全狗和360提权案例
291 0
|
小程序 前端开发 API
快递平台独立版小程序源码|带cps推广营销流量主+前端
快递平台独立版小程序源码|带cps推广营销流量主+前端
470 7
快递平台独立版小程序源码|带cps推广营销流量主+前端
|
存储 安全 搜索推荐
Java中的泛型
【9月更文挑战第15天】在 Java 中,泛型是一种编译时类型检查机制,通过使用类型参数提升代码的安全性和重用性。其主要作用包括类型安全,避免运行时类型转换错误,以及代码重用,允许编写通用逻辑。泛型通过尖括号 `<>` 定义类型参数,并支持上界和下界限定,以及无界和有界通配符。使用泛型需注意类型擦除、无法创建泛型数组及基本数据类型的限制。泛型显著提高了代码的安全性和灵活性。
155 8
|
存储 JavaScript
vue项目中页面跳转传参的方法
vue项目中页面跳转传参的方法
828 0