在向Promise添加监听器之后,我应该使用原始的Promise还是新的Promise
after adding a listener to a Promise, should I use the original promise or the new one?
我有一些javasrpt代码,它接受了现有的promise(比如说,fetch()返回的promise)并添加值(比如,then/catch监听器进行调试,或者更多):
let myFetch = function(url) {
return fetch(url).then(function(value) {
console.log("fetch succeeded: value=",value);
return value;
}.catch(function(reason) {
console.log("fetch failed: reason=",reason);
throw reason;
});
};
我发现自己修改了上面的代码,以便只有在某些条件成立时才添加侦听器:
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是另一个"然后"的简写)如上所述,或者它返回原来的承诺(添加了监听器)更有意义吗?换句话说,我正在考虑省略第二个"promise=",这样代码就会变成这样:
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;
};
这与以前的版本有什么不同吗?两者中的任何一个版本更可取吗?如果是,为什么?
如果您唯一的用例是在then
/catch
中记录一些东西,那么只要一切顺利,这就无关紧要了。如果出现异常,事情会变得更糟。考虑以下两个例子:
返回原始承诺
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)
});
结果是success
,内部then
中抛出的错误可能会在一些promise库中被吞噬(尽管最流行的库(如Bluebird)会处理此问题,并且会得到额外的错误Unhandled rejection Error: x
)。在某些环境中使用本机Promises时,该错误也可能被接受。
返回修改后的承诺
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)
});
现在的结果是error! Error: x
。
好吧,如果成功处理程序return
是值,而拒绝处理程序throw
是错误,那么这基本上就是promise的身份转换。
你不仅不需要做promise = promise.then
,甚至不需要返回值:
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;
};
一些像bluebird这样的承诺库为此提供了一个tap实用程序。唯一的问题是,如果fetch
添加了对承诺取消的支持,那么如果不链接if (some condition)
处理程序,则会破坏链。
您是承诺分支。在第二种情况下,您实际上将promise链分支为两个promise链,因为一旦调用者调用myFetch
:
myFetch("localhost").then(request => { /* use request */ } );
则promise
将对其调用.then
两次(一次在myFetch
内部进行控制台日志记录,另一次在此处)。
这很好。您可以任意多次调用同一promise上的.then
,并且每当promise
解析时,函数都将以相同的顺序一起执行。
但是,重要的是,每个函数都代表了原始承诺的一个分支,独立于其他分支。这就是为什么在console.log
之后不需要返回或重新抛出任何内容:没有人在该分支上侦听,特别是myFetch
的调用者不受影响。
这非常适合记录IMHO,但在进行更多操作时需要注意一些细微的时间和错误处理差异:
var log = msg => div.innerHTML += msg + "<br>";
var myFetch = url => {
var p = Promise.resolve({});
p.then(() => log("a")).then(() => log("b"));
return p;
}
myFetch().then(() => log("1")).then(() => log("2")).catch(log); // a,1,b,2
<div id="div"></div>
这会发射CCD_ 20。正如你所看到的,这里有两条链条在平行前进。当你想到promise
何时被解决时,这是有道理的,但这可能会令人惊讶。
另一个微妙之处是,错误处理也是针对每个分支的(一个分支永远不会让另一个分支失败)。事实上,上面的代码有一个错误。你发现了吗?.then(() => log("b"))
之后应该有一个catch
,否则在某些环境中,您在该分支中所做的任何错误都将无法处理或被吞噬。
- 使用 jQuery 的 .on 函数如何获取事件的原始元素
- 使用promise和mongoose对文档进行排序
- 使用jQuery从原始页面内容创建iframe
- 测试Angular Service解决错误回调中的promise
- 从客户端获取修改后的对象,并将其与服务器上的原始对象组合
- 节点协同与生成器和Promise并行流量控制
- 我如何制作一个JS函数,它可以从相似的原始颜色双向更改为某个颜色
- 根据是否解析了 Promise 从函数返回值
- 将一个方法转换为promise:Nodejs
- 函数在promise被解析后被调用,但Jasmine未通过测试.为什么?
- js promise没有正确关闭
- Angularjs使用“;这个“;promise内的关键字回调
- AngularJS和promise值在调用本地函数时的效果-未定义
- 查找仅适用于原始图像的图像放大算法的名称
- 如何在使用Javascript浏览网站时处理原始窗口
- 在ES6 Promise中,我应该在解决/拒绝之前使用return吗
- 以同步方式获取Javascript Promise的值
- markrwithlabel.js(第三方)原始文件链接断开
- 如何使用bluebird将原始数据与Promise.map的响应一起传递
- 在向Promise添加监听器之后,我应该使用原始的Promise还是新的Promise