Javascript 在将侦听器添加到承诺后,我应该使用原始承诺还是新承诺?

Javascript 在将侦听器添加到承诺后,我应该使用原始承诺还是新承诺?,javascript,promise,es6-promise,Javascript,Promise,Es6 Promise,我有一些javasript代码,它接受了现有的承诺 (例如,fetch()返回的承诺)并增加了值 (比如,然后/捕获侦听器进行调试,或者更多): 我发现自己正在修改上述代码,以便仅当某些条件为真时才添加侦听器: let myFetch = function(url) { let promise = fetch(url); if (some condition) { promise = promise.then(function(value) { console.log

我有一些javasript代码,它接受了现有的承诺 (例如,fetch()返回的承诺)并增加了值 (比如,然后/捕获侦听器进行调试,或者更多):

我发现自己正在修改上述代码,以便仅当某些条件为真时才添加侦听器:

let myFetch = function(url) {
  let promise = fetch(url);
  if (some condition) {
    promise = promise.then(function(value) {
      console.log("fetch succeeded: value=",value);
      return value;
    }.catch(function(reason) {
      console.log("fetch failed: reason=",reason);
      throw reason;
    });
  }
  return promise;
};
现在我想知道,myFetch返回“then”返回的新承诺真的有意义吗 (实际上catch是另一个“then”的缩写)如上所述, 或者,它返回最初的承诺(添加了侦听器)会更有意义吗? 换句话说,我想省略第二个“承诺”, 因此,代码将改为如下所示:

let myFetch = function(url) {
  let promise = fetch(url);
  if (some condition) {
    promise.then(function(value) {
      console.log("fetch succeeded: value=",value);
      return value;
    }.catch(function(reason) {
      console.log("fetch failed: reason=",reason);
      throw reason;
    });
  }
  return promise;
};
这与以前的版本有很大不同吗?
这两个版本是否更可取,如果是,原因是什么?

好吧,如果成功处理程序
返回值,而拒绝处理程序
抛出错误,那么这基本上就是承诺的身份转换

您不仅不需要这样做
promise=promise。然后
您甚至不需要返回值:

let myFetch = function(url) {
  let promise = fetch(url);
  if (some condition) {
    promise.then(function(value) {
      console.log("fetch succeeded: value=",value);
    }.catch(function(reason) {
      console.log("fetch failed: reason=",reason);
    });
  }
  return promise;
};
也就是说,如果您使用的是ES6和let,那么您可以使用箭头函数,这样做会更好一些:

let myFetch = function(url) {
  let promise = fetch(url);
  if (some condition) {
    promise.then(value => console.log("fetch succeeded: value=",value))
          .catch(reason => console.log("fetch failed: reason=",reason));
  }
  return promise;
};

一些promise库(如bluebird)为此提供了tap实用程序。唯一的问题是,如果ever
fetch
增加了对承诺取消的支持,那么如果没有链接,那么您就是在用
if(某些条件)
处理程序断开链

如果您唯一的用例是在
中记录一些东西,那么
/
catch
——只要一切顺利,它就不重要了。如果出现异常,事情会变得更糟。考虑这两个例子:

返还原承诺 结果是
success
,然后在内部
中抛出的错误可能会被一些promise库吞没(尽管最流行的库(如Bluebird)会处理这个问题,并且您会得到额外的错误
未处理的拒绝错误:x
)。 使用时,错误也可能被忽略

返回修改后的承诺 现在结果是
错误!错误:x

您正在执行分支。在第二种情况下,实际上是将承诺链分支为两个承诺链,因为一旦调用方调用
myFetch

myFetch("localhost").then(request => { /* use request */ } );
然后,
promise
将拥有
。然后
调用它两次(一次在
myFetch
内执行控制台日志记录,然后在此处再次调用)

这很好。您可以调用
。然后根据相同的承诺调用
,次数可以根据您的喜好而定,并且每当
承诺
解析时,这些函数将以相同的顺序一起执行

但是,重要的是,每个函数都代表了原始承诺的一个分支,独立于其他分支。这就是为什么您不需要在
控制台.log之后返回或重新播放任何内容的原因:没有人监听该分支,特别是
myFetch
的调用者不受影响

这非常适合记录IMHO,但在执行其他操作时,需要注意一些细微的时间和错误处理差异:

var log=msg=>div.innerHTML+=msg+“
”; var myFetch=url=>{ var p=Promise.resolve({}); p、 然后(()=>log(“a”)。然后(()=>log(“b”); 返回p; } myFetch()。然后(()=>log(“1”))。然后(()=>log(“2”))。catch(log);//a、 1、b、2

在这种情况下,OP在这两种情况下都正确地转发成功/失败,而且他们使用的唯一函数从未抛出。很高兴再次见到你:)@BenjaminGruenbaum嗯。。。如果我做了一些愚蠢的事情,比如调用console.warning(),而我的意思是console.warn(),它会抛出错误,但我永远不会这么做;-)一般来说,我没有预料到的抛出情况的可能性,就像这样,让我觉得也许最好使用“返回修改的承诺”版本,这样意外的事情就不会被吞没;你认为呢?对于任何一个像样的库,意想不到的事情都不会被吞没——包括但不限于原生承诺(带有未处理的退出事件)、蓝鸟、Q和其他库。啊,你说得对!我原以为native promises会接受它,但我只是尝试了一下,得到了一条“Uncaught(in promise)”错误消息,就像你预测的那样,如果我读对了的话。因此,如果Michal注意到本机异常(以及Q和其他库)也不会吞并错误,那么他的答案可能会有所改进。因此,至少对于纯粹的听众来说,这对我来说是有利于“回归原始承诺”的,因为它既漂亮又简洁,没有明显的缺点;然而,我的印象是,本机承诺不应该再吞下错误,如果任何实现仍然吞下错误,那么这只是一个将被修复的错误,或者是由于垃圾收集延迟而产生的错觉。的可能重复(使用async/await,但问题是相同的).谢谢你的回答和思考的极好的微妙的例子。必须在两个好答案之间做出选择。
function myFetch() {
    let promise = new Promise(function (resolve, reject) {
        resolve(100);
    });
    promise.then(function () { throw new Error('x'); });
    return promise;
}

myFetch().then(function () {
    console.log('success!');
}).catch(function (e) {
    console.error('error!', e)
});
function myFetch() {
    let promise = new Promise(function (resolve, reject) {
        resolve(100);
    });
    promise = promise.then(function () { throw new Error('x'); });
    return promise;
}

myFetch().then(function () {
    console.log('success!');
}).catch(function (e) {
    console.error('error!', e)
});
myFetch("localhost").then(request => { /* use request */ } );