什么是显式承诺构造反模式以及如何避免它?

2024-11-02 20:59:00
admin
原创
165
摘要:问题描述:我正在编写的代码执行以下操作:function getStuffDone(param) { return new Promise(function(resolve, reject) { myPromiseFn(param+1) .then(function...

问题描述:

我正在编写的代码执行以下操作:

function getStuffDone(param) {
    return new Promise(function(resolve, reject) {
        myPromiseFn(param+1)  
        .then(function(val) { 
            resolve(val);     
        }).catch(function(err) {
            reject(err);
        });
    });
}

或者:

显示代码片段

function getStuffDone(param) {
    var d = Q.defer(); /* or $q.defer */
    // or = new $.Deferred() etc.
    myPromiseFn(param+1)
    .then(function(val) { /* or .done */
        d.resolve(val);
    }).catch(function(err) { /* .fail */
        d.reject(err);
    });
    return d.promise; /* or promise() */
}

Run code snippetHide resultsExpand snippet

有人告诉我这分别被称为“延迟反模式”或“Promise构造函数反模式”,这段代码有什么不好,为什么称之为反模式?


解决方案 1:

Esailija提出的延迟反模式(现在是显式构造反模式)是初学 Promise 的人经常犯的一个反模式,我第一次使用 Promise 时也犯过这个错误。上述代码的问题在于,它没有利用 Promise 链式传递这一事实。

Promises 可以与 链接.then,并且您可以直接返回 Promises。您的代码getStuffDone可以重写为:

function getStuffDone(param){
    return myPromiseFn(param+1); // much nicer, right?
}

Promises 的作用是让异步代码更易读,并使其行为与同步代码相似,但又不隐藏这一事实。Promises 表示对一次性操作值的抽象,它们抽象了编程语言中语句或表达式的概念。

仅当您将 API 转换为承诺且无法自动执行时,或者当您编写以这种方式更容易表达的聚合函数时,才应该使用延迟对象。

引用 Esailija 的话:

这是最常见的反模式。如果你不真正理解 Promise,并认为它们是被美化的事件发射器或回调实用程序,就很容易陷入这种模式。让我们回顾一下:Promise 是关于让异步代码保留同步代码的大部分丢失属性,例如扁平缩进和一个异常通道。

解决方案 2:

它有什么问题?

但这个模式有效!

你真幸运。不幸的是,它可能没有,因为你可能忘记了一些极端情况。在我见过的超过一半的案例中,作者忘记了处理错误处理程序:

function bad() {
    return new Promise(function(resolve) {
        getOtherPromise().then(function(result) {
            resolve(result.property.example);
        });
    })
}

如果另一个承诺被拒绝,这将不会被注意,而不是传播到新的承诺(在那里它会被处理) - 并且新的承诺永远处于待处理状态,这可能会导致泄漏。

同样的事情也发生在回调代码导致错误的情况下 - 例如,当result没有property并且抛出异常时。这将得不到处理,导致新的承诺无法解决。

相比之下,使用.then()会自动处理这两种情况,并在发生错误时拒绝新的承诺:

function good() {
    return getOtherPromise().then(function(result) {
        return result.property.example;
    })
}

延迟反模式不仅麻烦,而且容易出错。使用.then()链式调用更安全。

但我已经处理好一切了!

真的吗?很好。但是,这将非常详细和丰富,特别是如果您使用支持其他功能(如取消或消息传递)的 Promise 库。或者也许将来会这样,或者您想将您的库换成更好的库?您不会想为此重写代码。

库的方法 ( then) 不仅原生支持所有功能,还可能进行某些优化。使用它们可能会让您的代码运行得更快,或者至少允许通过库的未来修订进行优化。

我该如何避免?

因此,每当您发现自己手动创建PromiseDeferred涉及已存在的承诺时,请先检查库 API。延迟反模式通常由那些将承诺 [仅] 视为观察者模式的人应用 - 但承诺不仅仅是回调:它们应该是可组合的。每个像样的库都有许多易于使用的函数,用于以各种可以想到的方式组合承诺,处理所有您不想处理的低级内容。

如果您发现需要以新的方式组合一些承诺,而现有辅助函数不支持这种方式,那么使用不可避免的 Deferred 编写自己的函数应该是您的最后选择。考虑切换到功能更强大的库,和/或针对当前库提交错误。它的维护者应该能够从现有函数中派生出组合,为您实现新的辅助函数和/或帮助识别需要处理的边缘情况。

解决方案 3:

七年后的今天,这个问题有了更简单的答案:

如何避免显式构造函数反模式?

使用async functions,然后await每个 Promise!

不需要手动构建像这样的嵌套 Promise 链:

function promised() {
  return new Promise(function(resolve) {
    getOtherPromise().then(function(result) {
      getAnotherPromise(result).then(function(result2) {
        resolve(result2);
      });
    });
  });
}

只需转动你的函数async并使用await关键字来停止函数的执行,直到 Promise 解析为止:

async function promised() {
   const result =  await getOtherPromise();
   const result2 = await getAnotherPromise(result);
   return result2;
}

这有多种好处:

  • 调用该async函数始终返回一个 Promise,该 Promise 使用返回值解析,如果异步函数内部抛出错误则拒绝

  • 如果awaited Promise 拒绝,错误就会在异步函数内部引发,因此您可以像处理try { ... } catch(error) { ... }同步错误一样处理它。

  • 你可以await在循环和 if 分支中使用它,这样就可以简化大部分 Promise 链逻辑

  • 尽管异步函数的行为与 Promises 链非常相似,但它们更易于阅读(也更容易推理)

我如何await回电?

如果回调仅回调一次,并且您调用的 API 尚未提供 Promise(大多数都提供!)这是使用 Promise 构造函数的唯一原因:

 // Create a wrapper around the "old" function taking a callback, passing the 'resolve' function as callback
 const delay = time => new Promise((resolve, reject) =>
   setTimeout(resolve, time)
 ); 

 await delay(1000);

如果await停止执行,调用是否async function直接返回结果?

不可以。如果您调用异步函数,则始终会返回 Promise。然后您也可以await在异步函数内返回该 Promise。您无法在同步函数内等待结果(您必须调用.then并附加回调)。

从概念上讲,同步function总是在一项作业中运行至完成,而 则async function同步运行直至达到await,然后它们在另一项作业中继续运行。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用