删除promise依赖项

时间:2016-11-25 05:27:33

标签: javascript node.js bluebird

我知道承诺的力量,但我有几个同步的旧功能:

function getSomething() {
  return someExternalLibrary.functionReturnsAValue()
}

console.log(getSomething()); // eg prints 'foo'

不幸的是,当someExternalLibrary更新时,它已删除了functionReturnsAValue(),并将functionReturnsAPromise()混为一谈:

function getSomething() {
  return someExternalLibrary.functionReturnsAPromise()
}

console.log(getSomething());  // now prints '[object]'

当然,这绝对打破了所有写入的东西,这取决于过去的简单值。

显然,我更喜欢两件事:

  1. 要求原始库保持同步返回值。 (不会发生 - 他们拒绝了b / c)
  2. 实际等待值的方法
  3. 我读过很多关于为什么承诺很好, ad nauseam 的文章,但简单的事实是:如果我接受承诺,我真正做的就是将代码的其他部分改为承诺,然后必须处理价值的承诺...

    有没有办法(在nodejs中)实际等待承诺让自己在一起?

    我能找到的最好的就是使用协同程序和屈服,但实际上,它还在推卸责任。为了清楚起见,我希望函数getSomething继续返回一个值。有办法吗?

    显然,我担心我对Promises有些误解......

    该应用程序适用于非浏览器实现,仅从命令行运行。我一直试图理解bluebird's reflect()可能会有什么帮助,但无济于事。

    (是的,我知道这个问题已经多次以各种格式提出,但我无法找到核心问题的合适答案。如果有的话,我正在寻找与this question相反。我能找到的最相关(但无益)的问题是:Managing promise dependencies。)

2 个答案:

答案 0 :(得分:0)

有发电机功能的概念。这些是语法(星号表示法)和语义中的一种特殊功能。与常规函数不同,生成器函数返回的东西也是ECMAScript的新东西:迭代器。迭代器恰好是专门用于迭代的对象,例如,迭代器。与循环的全新...它们也可以通过调用它们的“下一个”方法手动迭代。每个这样的调用都会产生一个包含两个属性的对象:'value'(迭代器的当前值)和'done'(一个布尔值,表示我们是否达到了iterable的最后一个值)。但是,关于生成器函数的最好的事情是它们能够在每次遇到关键字“yield”时暂停执行。让我们一起看看它们如何协同工作:

'use strict';

let asyncTask = () =>
  new Promise((resolve, reject) => {
    if (Math.random() > 0.5) {
      resolve(1);
    } else {
      reject(new Error('Something went wrong'));
    }
  });

let makeMeLookSync = fn => {
  let iterator = fn();
  let loop = result => {
    !result.done && result.value.then(
      res => loop(iterator.next(res)),
      err => loop(iterator.throw(err))
    );
  };

  loop(iterator.next());
};

makeMeLookSync(function* () {
  try {
    let result = yield asyncTask();

    console.log(result);
  } catch (err) {
    console.log(err.message);
  }
});

答案 1 :(得分:0)

简短回答

我被反复告知:你无法撤销已被宣告的功能。

编辑:即将推出的解决方案

ES2017(虽然仍然是草案)似乎在使宣传的代码更易于使用方面取得了很大进展: https://ponyfoo.com/articles/understanding-javascript-async-await

似乎还有一个节点库可以为这种支持做好准备:https://github.com/normalize/mz

使用这种方法,让apis转换为Promises不会那么糟糕(虽然看起来仍然会使代码库的其余部分中毒):

const fs = require('mz/fs')

async function doSomething () {
  if (await fs.exists(__filename)) // do something
}

这个答案的其余部分只是对问题的一般性评论。

为什么我们需要解决方案

让我们从一个传统的同步代码样本开始,有三种来自更多老式'到了更新的':

这是传统的javascript方式,需要基于异常的编程来处理意外错误:

function getSomething() {
    if (someproblem) throw new Error('There is a problem');
    return 'foo';
}

然而,添加try/ catch语句变得非常费力且乏味,非常快。

随着node.js的出现,回调变得流行,很好地避开了这个问题,因为每个调用者都明确被迫在同一个回调中处理错误条件。这意味着调用者代码中的错误更少:

function getSomething(callback) {
    if (callback) {
        if (someproblem) 
            callback(new Error('There is a problem'), null);
        else 
            callback(null, 'foo');
    }
    return 'foo';
}

然后,经过一些出牙问题,node.js迅速证明了自己的服务器端通信,人们对异步解决方案提供的速度感到惊讶。像Express和Meteor这样的节点应用程序框架越来越多,重点关注这一点。

不幸的是,使用相同的回调方案很快就变得很麻烦,处理异步代码的开发人员开始使用Promises来努力线性化代码,使其可读,就像传统的(try / catch)代码一样。

问题在于它过于依赖。每个人都开始认为Promise是要走的路。就个人而言,我称之为代码库中的毒药。一旦你拥有使用Promises的任何,你的整个代码库就必须变为异步。恕我直言,这并不总是明智的,也不是切实可行的解决方案。

所有副作用中最糟糕的是上述函数即使完全同步也可以用Promises编写:

var bluebird = require('bluebird');

function getSomething() { 
    // IMHO, this is ridiculous code, but is increasingly popular.
    if (someproblem) return Promise.reject(new Error('There is a problem'));
    return Promise.resolve('foo');
}

对于那些怀疑这是一个问题的人,或许应该看看SO问题:How do I convert an existing callback API to promises?。特别注意#3,节点式回调。

所以,对于任何关心的人,我想建议需要一个“避孕药”。为了承诺。我敦促我们需要的不仅仅是承诺:我们需要结果,有时需要及时。

查看默认的node.js api。它不使用Promises。它提供对api的适当部分的同步和异步调用(例如文件系统)。

对于那些想要倾向于回答这个问题的人:这是你的特权,但是当Promise 答案的时候有明显的问题,我强烈认为有些情况我们需要能够重新同步解耦代码。

我也为这篇博客文章道歉'风格回答。