返回

函数式参数传递:TypeScript/JavaScript实践

javascript

TypeScript/JavaScript 函数式参数传递:实践分析

问题概述

函数接收其他函数作为参数是函数式编程的核心概念。在 TypeScript/JavaScript 中,我们经常需要创建这种高阶函数。 一个常见的场景是创建一个服务,例如用于显示确认对话框,其中需要接受确认和取消时执行的操作函数作为参数。 此问题旨在评估接收函数参数的 abrirModalConfirm 方法的实现方式。 这种方法被广泛应用于前端开发中,如控制用户交互流程,自定义模态框等。 这就需要分析该方法是否符合良好的编程实践。

问题剖析

提供的代码使用回调函数的方式处理模态框操作。当用户在模态框上点击“确定”或“取消”按钮时,它根据用户的操作,执行相应的回调函数 (onConfirmonCancel)。 虽然这种方法是可行的,但潜在的缺陷可能隐藏在异步代码管理中。特别地,当业务逻辑复杂,链式调用多个 async/await 时,基于回调函数的处理方式可能迅速造成“回调地狱”。 如果考虑进一步增强功能(例如添加加载状态、错误处理)或与其它模块进行更复杂的集成,这种代码风格会变得更难维护。 此时考虑其他模式如 Promise 也许是更好的方式。

解决方案与实践

方案一:Promise 模式

使用 Promise 可以改善回调代码的结构和可读性。 Promise 允许我们处理异步操作的最终结果(成功或失败),这避免了深层回调嵌套的问题。使用 async/awaitPromise 搭配,更是进一步简化了异步操作的代码逻辑。

原理: 将打开模态框和等待用户操作视为异步操作,返回一个 Promise。 当模态框关闭时,Promise 可以通过成功或失败的方式处理 onConfirmonCancel 事件,并将控制权传递给调用方。

实现:

import { Injectable } from '@angular/core';
import { ModalService } from './modal.service';
import { ModalConfirmComponent } from '../components/modal-confirm/modal-confirm.component';


@Injectable({
  providedIn: 'root'
})
export class ModalConfirmService {
  constructor(
    private modalService: ModalService,
  ) {}

   abrirModalConfirm(message: string): Promise<boolean> {
    return new Promise((resolve, reject) => {
          this.modalService.abrirModal(ModalConfirmComponent, {
                data: {
                   message: message,
              }
          }).onClose.subscribe((status: string) => {
                  if (status === 'accepted') {
                    resolve(true);
                  } else {
                   resolve(false);
                }
            });
    });
  }
}

使用方法:

//调用该服务时
this.modalConfirmService.abrirModalConfirm("Are you sure?").then((result)=>{
   if (result) {
       //Do something if confirmed.
       console.log("user confirmed")
    }
   else{
    //Do something if cancelled
     console.log("user cancelled")
    }
})

步骤:

  1. 将原来方法改为返回 Promise
  2. 将模态框关闭时的事件监听中调用 resolve() 或者 reject()。这里我们选择简化使用resolve传递Boolean值来表明用户行为
  3. 可以在调用处 使用 then()catch() 处理确认与取消行为。

安全建议:

  • 对于可能长时间运行的操作,Promise 配合timeout进行操作超时控制,保证系统的稳定运行
  • 为防止意外错误,请始终捕获 promise 的异常,并在用户界面中向用户反馈异常信息

方案二:Observable 流式模式

RxJSObservable 是处理异步事件的另一利器。这种模式非常适合处理一系列可能随着时间推移而发生的事件。 Observable提供了多种操作符,可以方便我们管理、转换以及过滤异步流中的数据。它让逻辑更清晰,结构更好,同时提供了取消正在进行中的异步操作的灵活性。

原理 : Observable可以像数据流一样发射数据。我们把模态框的事件(如onConfirmonCancel)作为数据流处理。调用者订阅此流,来根据用户操作响应。

实现:

import { Injectable } from '@angular/core';
import { ModalService } from './modal.service';
import { ModalConfirmComponent } from '../components/modal-confirm/modal-confirm.component';
import {Observable, Subject } from 'rxjs';

@Injectable({
providedIn: 'root'
})
export class ModalConfirmService {
 constructor(private modalService: ModalService) {}

abrirModalConfirm(message: string): Observable<string> {
  const subject = new Subject<string>();
   this.modalService.abrirModal(ModalConfirmComponent, {
      data: {
            message: message,
        }
    }).onClose.subscribe((status: string) => {
          subject.next(status);
          subject.complete();
      });
  return subject.asObservable();
}
}

使用方法:

// 调用该服务时
this.modalConfirmService.abrirModalConfirm("确定要执行此操作吗?").subscribe((status) => {
  if (status === 'accepted') {
     console.log("user confirmed");
    }
   else{
        console.log("user cancelled");
    }
});

步骤:

  1. 创建 Subject 实例,作为数据的通道。
  2. 将原来方法返回Observable 类型数据。
  3. 在模态框关闭时的事件监听中,使用 next 方法将结果传入 Subject 并使用 complete() 完成数据发射。
  4. 在调用处通过 subscribe()订阅这个 Observable,并处理响应事件。

安全建议:

  • Observable可以通过使用take(1)限制值的产生次数, 避免Observable中没有complete()导致的内存泄漏.
  • 当订阅的组件或服务销毁时,记得取消订阅(unsubscription)来防止潜在的内存泄露。

结论

针对函数参数的处理,上述两种方案都可以有效地实现模态框功能, 并同时避免传统回调模式带来的问题。Promise 适合于处理一次性的异步操作。 而Observable 在处理流式数据时更有优势。在实际开发中,需要根据项目的实际需求和团队的技术偏好来选择最适合的模式。同时需要留意使用过程中的安全性,增强软件的健壮性和稳定性。