我有许多函数可能会或可能不会返回Promise,可能会也可能不会失败,如下例所示:
let goodFun = (fruit) => `I like ${fruit}`;
let badFun = (fruit) => {
throw `${fruit} is spoiled!`;
};
let badPromise = (fruit) => new Promise( (fulfil, reject) => {
reject(`Promise failed with ${fruit}`);
});
let goodPromise = (fruit) => new Promise((fulfil, reject) => {
fulfil(`Promise succeeded with ${fruit}`);
});
因为每个函数可能会也可能不会返回一个可能会或可能不会失败的promise,我从another StackOverflow post修改了executeSafe
,它将一个函数及其参数作为参数,然后宣传函数及其结果:
let executeSafe =
(fun, ...args) => Promise.resolve().then(() => {
return fun(...args);
});
我的目标是使用asyncFun
函数等待执行一系列Promisified函数,然后返回执行它们的任何函数:
let asyncFun =
(fruit) =>
Promise.all([badFun, goodFun, badPromise, goodPromise].map(
fun => executeSafe(fun, fruit)
)
);
asyncFun
旨在运行前面描述的众多功能,其中一些我实际上希望看到失败。为了适应这一点,我的asyncFun
函数有一个catch
子句。此子句仅适用于badFun
,不适用于badPromise
。 then
子句永远不会有效。
let executor = () => {
let fruitsArr = ["banana", "orange", "apple"];
let results = [];
for (let fruit of fruitsArr)
results.push(
asyncFun(fruit)
.then(res => {
console.log(res);
})
.catch(error => {
console.log(`Error: ${error}`);
})
);
return Promise.all(results);
};
在执行者的调用中放置catch
子句甚至不会捕获badFun
错误以外的任何其他内容。
executor()
.catch(error => console.log("Failed miserably to catch error!"));
let goodFun = (fruit) => {
return `I like ${fruit}`;
};
let badFun = (fruit) => {
throw `${fruit} is spoiled!`;
};
let badPromise = (fruit) => Promise.resolve().then(() => {
throw `Promise failed with ${fruit}`;
});
let goodPromise = (fruit) => Promise.resolve().then(() => {
return `Promise succeded with ${fruit}`;
});
let executeSafe =
(fun, ...args) => Promise.resolve().then(() => {
return fun(...args);
});
let asyncFun = (fruit) => Promise.all([badFun, goodFun, badPromise, goodPromise].map(fun => executeSafe(fun, fruit)));
let executor = () => {
let fruitsArr = ["banana", "orange", "apple"];
let results = [];
for (let fruit of fruitsArr)
results.push(
asyncFun(fruit)
.then(res => {
console.log(res);
})
.catch(error => {
console.log(`Error: ${error}`);
})
);
return Promise.all(results);
};
executor()
.catch(error => console.log("Failed miserably to catch error!"));
问题:
then
中的catch
和asyncFun
条款按预期工作?答案 0 :(得分:3)
这里的问题是你误解了Promise.all()
的工作原理。它的工作方式是,如果所有的承诺成功,它将解析为一个值数组。如果中的任何失败,则会拒绝发生的第一个错误。
你似乎期待的是,then
中成功的那些被捕获,而失败者被catch
捕获,是不可能的。承诺要么解决一次,要么拒绝一次。它不会同时执行这两项操作,并且不会多次执行其中一项操作。 Promise.all()
返回单个承诺,以便解决或拒绝。
第三方承诺库确实有“解决”一系列承诺的方法 - 基本上等到他们完成所有事情(成功或失败),然后解析为结果数组。您可以像这样实现它:
// values is an array of promises and/or non-promise values
function allSettled(values) {
let settle =
value => Promise.resolve(value)
.then(result => ({ state: "fulfilled", value: result }))
.catch(error => ({ state: "rejected", reason: error }));
return Promise.all(values.map(settle));
}
// example usage
allSettled(['hello', 'goodbye', Promise.resolve('good'), Promise.reject('bad')])
.then(results => console.log(results));
然后您可以像下面一样使用它。
在一个不相关的说明中,我还修改了您的方法,以便您不需要executeSave
的{{1}}的修改版本(我认为这是一种令人费解的方式) 。你可以创建使用之前的参数的函数,然后将它们传递给...args
:
_executeSafe_
附加说明 - 如果您想使用Jared Smith答案中的let goodFun = (fruit) => `I like ${fruit}`;
let badFun = (fruit) => {
throw `${fruit} is spoiled!`;
};
let badPromise = (fruit) => Promise.reject(`Promise failed with ${fruit}`);
let goodPromise = (fruit) => Promise.resolve(`Promise succeeded with ${fruit}`);
let executeSafe = fun => Promise.resolve().then(fun);
function allSettled(values) {
let settle =
value => Promise.resolve(value)
.then(result => ({ state: "fulfilled", value: result }))
.catch(error => ({ state: "rejected", reason: error }));
return Promise.all(values.map(settle));
}
let asyncFun =
(fruit) =>
allSettled([badFun, goodFun, badPromise, goodPromise]
.map(fun => () => fun(fruit))
.map(executeSafe)
);
asyncFun("orange").then(results => console.log(results));
函数,那么您可以将promisify
函数更改为:
asyncFun
答案 1 :(得分:0)
所以这很有效,抓住了。如果传递给promisify
的函数返回一个promise,它就会被传递给链。
var fnThatThrows = s => { throw new Error(s) };
var identity = x => x;
var promisify = f => (...args) => new Promise((res, rej) => {
try {
res(f(...args));
} catch (e) {
rej(e);
}
});
var rejected = promisify(fnThatThrows);
rejected("foo").then(_ => console.log("shouldn't see")).catch(e => console.log(e)); // logs error
var succeded = promisify(identity);
succeeded("foo").then(val => console.log(val)); // logs 'foo'
如果来自参数函数的promise被拒绝,那么它也会被传递:
var returnsBadPromise = s => Promise.reject(new Error(s));
promisify(returnsBadPromise)("foo").catch(e => console.log(e)); // logs error