Javascript 承诺中间件
最近我不得不写一些奇怪的代码。我不确定,也许我在重新发明轮子 有没有简单的方法将中间件放入承诺链 假设我们有一些承诺,例如,可能是axios.get'/users'。 我们想对结果做点什么,然后再做点别的。 假设这些操作位于应用程序的不同部分,并且我们不能将它们组合成一个函数。 更重要的是,其中一些只是同步的商店更新,不返回任何内容,另一个可能返回承诺 可以写Javascript 承诺中间件,javascript,node.js,promise,Javascript,Node.js,Promise,最近我不得不写一些奇怪的代码。我不确定,也许我在重新发明轮子 有没有简单的方法将中间件放入承诺链 假设我们有一些承诺,例如,可能是axios.get'/users'。 我们想对结果做点什么,然后再做点别的。 假设这些操作位于应用程序的不同部分,并且我们不能将它们组合成一个函数。 更重要的是,其中一些只是同步的商店更新,不返回任何内容,另一个可能返回承诺 可以写 axios .get('/users') .then((result) => { doSomething(resu
axios
.get('/users')
.then((result) => {
doSomething(result)
})
.then((result) => {
doSomethingElse(result)
})
这不起作用,因为第一个然后不返回承诺,所以第二个然后将不会收到结果。
无承诺同步操作的正确代码为:
axios
.get('/users')
.then((result) => new Promise((resolve, reject) => {
doSomething(result)
resolve(result)
}))
.then(result) => new Promise((resolve, reject) => {
doSomethingElse(result)
resolve(result)
})
...etc...
但我不喜欢这样。我一个人吗?我想要一些类似于:
axios
.get('/users')
.thenMiddleware(doSomething)
.then((result) => {
doSomethingElse()
})
这意味着我们要用get'/users'的结果运行doSomething,如果没有错误,我们要用get'/users'的结果再次调用下一个chain函数
关于错误:我只会考虑错误,如果一个行动返回一个承诺,这个承诺拒绝。
这有意义吗
这就是我写的函数:
const promiseMiddleware = (target) => function(...args) {
return new Promise((resolve, reject) => {
if (typeof target === 'function') {
target = target.apply(this, args)
}
if (typeof target === 'object' && typeof target.then === 'function') {
// Middleware does not count the result of inner promise, it triggers the promise chain to continue with the incomming data instead.
// But if the inner promise rejects, middleware returns an inner error.
target.then((targetResult) => {
// So we don't use targetResult here, we just resolve with the incomming args.
resolve.apply(this, args)
}).catch(reject)
} else {
resolve.apply(this, args)
}
})
}
我们可以像这样使用它。这是正确的方法吗?还是我忽略了在我的例子中可以使用的一些明显的承诺?您正在寻找的中间件概念是then或catch回调本身。然后,抓住一个新的承诺,让我们称之为新的。如果您提供给then/catch的回调返回承诺或更一般的thenable,则thenP将解析为回调返回的一个,这意味着它将根据该承诺/thenable的功能得到满足或拒绝。如果回调返回一个非thenable的值,例如,不是承诺,则使用该值来实现p。如果回调引发异常,则会将p与该异常一起拒绝 如果术语thenable不太熟悉,或者您不清楚fulfill和resolve之间的区别,我会在我的博客中使用promise术语 没有承诺的同步操作的正确代码是 否,正确的代码是从中返回: 如果只是函数调用,也可以简单地编写:
axios
.get('/users')
.then(doSomething)
.then(doSomethingElse);
如果doSomething和doSomethingElse也是异步的,请确保它们返回承诺。如果没有,则上述方法有效,或者您可以将其结合使用:
// Assumes `doSomething` is not asynchronous
axios
.get('/users')
.then(result => doSomethingElse(doSomething(result)));
在您询问的评论中:
如果doSomething不返回任何值怎么办?那么doSomethingElse将不会收到get
承诺的主要概念之一是,它们是一条管道,管道中的每一步都可能改变通过它的内容。如果管道中需要一个不转换分辨率值的段,则可以将其与下一个段(如果不是异步的)组合,或者让该段返回它接收到的内容(如果是):
// (1) If `doSomething` ISN'T asynchronous or it is but you don't care
// that `doSomething` and `doSomethingElse` run in parallel if it is
axios
.get('/users')
.then(result => {
doSomething(result);
return doSomethingElse(result);
});
或
后者也可以写成:
// (2.2) Also if `doSomething` IS asynchronous and you want to wait for it but
// you don't want its result
axios
.get('/users')
.then(result => doSomething(result).then(result))
.then(doSomethingElse);
请注意,2.1和2.2仍将考虑剂量测定的拒绝。如果你想完全忽略其中发生的事情,那么:
// (3) If `doSomething` IS asynchronous and you want to wait for it but
// you don't want its result AND you want to ignore rejections
axios
.get('/users')
.then(result => doSomething(result).then(result, result))
// Change is here -----------------------------^^^^^^^^
.then(doSomethingElse);
将拒绝转换为具有结果的解决方案
旁注:记住承诺的规则之一是,你要么将承诺退还给你的来电者,要么自己处理拒绝。上面没有拒绝处理程序,但是您需要在生产代码中使用它们,或者您需要将链的结果返回到具有拒绝处理程序的内容。当您处于承诺链中时,您不必返回承诺。如果在链内执行异步调用,则只需返回承诺 你可以这么做
axios
.get('/users')
.then((result) => {
return doSomething(result);
})
.then((result) => {
return doSomethingElse(result);
})
假设您有一个异步回调风格的调用,那么您应该执行该调用
axios
.get('/users')
.then((result) => {
return new Promise((resolve, reject) => {
doSomething(result, (err, result) => {
return err ? reject(err) : resolve(result);
});
});
})
.then((result) => {
return doSomethingElse(result);
})
这很简单
如果您编写了中间件doSomething函数,那么只需让它返回结果而不改变它。例如,
function doSomething(result){
// here i do tons of things with the result but i don't mutate it
return result;
}
那么您的代码可能看起来像
axios
.get('/users')
.then(doSomething) // this will pass result to the next then
.then(doSomethingElse) // stage automatically wrapped in a promise
顺便说一句,你不需要做like.thenres=>{doStgres}只要做like.thendoStg就行了
然而,如果你对中间件的doSomething功能没有任何控制权,那么你所要做的就是
axios
.get('/users')
.then(res => (doSomething(res), res)) // this will pass result to the next then
.then(doSomethingElse) // stage automatically wrapped in a promise
注意:当您只有少量说明时,请使用箭头功能。我不喜欢带箭头的大括号,而是更喜欢逗号运算符。所以,
res => (doSomething(res), res)
本质上与,
res => {doSomething(res);
return res;}
抱歉,这里有几个输入错误,您可能必须点击刷新。好的,但是如果doSomething没有返回任何值呢?那么doSomethingElse无论如何都不会收到get的结果。@Kasheftin您只需要让它返回值,比如说,包装它:value=>{doSomething;return value;}@Kasheftin:AKX基本上是正确的,这取决于doSomething是否是异步的,以及是否要等待它的结果。为了更全面地回答这个问题,我增加了答案。
res => (doSomething(res), res)
res => {doSomething(res);
return res;}