是否可以从方法中返回任务,该方法首先调用多个Task<T>
返回方法,然后不使用await
返回包含先前调用结果的某种类型?
例如,以下内容很简单:
public Task<SomeType> GetAsync() => FirstOrDefaultAsync();
但是,我想做这样的事情:
public Task<SomeType> GetAsync()
{
var list = GetListAsync(); // <-- Task<List<T>>
var count = GetCountAsync(); // <-- Task<int>
return new SomeType // <-- Obviously compiler error
{
List /* <-- List<T> */ = list, // <-- Also compiler error
Count /* <-- int */ = count, // <-- Also compiler error
};
}
是否可以这样做而不必写:
public async Task<SomeType> GetAsync()
{
return new Type2
{
List = await GetListAsync(),
Count = await GetCountAsync(),
};
}
答案 0 :(得分:7)
坦白说,问题中已经存在的版本是正确:
import App from './App';
require("mapbox-gl-js-mock");
jest.mock('mapbox-gl/dist/mapbox-gl', () => ({
App: () => ({}),
}));
describe('<App />', () => {
let shallow;
beforeEach(() => {
shallow = createShallow({ dive: true });
});
it('renders without crashing', () => {
const wrapper = shallow(<App />);
expect(wrapper.find('.MapBox')).toExist();
});
});
我知道您问“不使用等待”,但是:避免等待的技巧是次佳;特别是,您应该几乎从不使用public async Task<SomeType> GetAsync()
{
return new Type2
{
List = await GetListAsync(),
Count = await GetCountAsync(),
};
}
-这是旧版API,并且ContinueWith
实现现已针对Task
(而非{{1})进行了优化}。
至:
因为我读到多次等待不利于性能。我尝试等待上次通话
否;一旦您有一个未完成等待,您拥有多少便几乎没有关系-他们实际上是免费的。不完整的await
相对于零的问题与ContinueWith
相当,因此:避免await
并不会带来任何收益。
结论:只需使用ContinueWith
。它更简单,更直接,并且内部对此进行了优化。
作为次要优化,您可能要添加await
,即
await
或者它们是否应同时运行,并且实现支持它:
ConfigureAwait(false)
答案 1 :(得分:0)
您可以将Task.WhenAll
与Task.ContinueWith
一起使用。
public Task<SomeType> GetAsync()
{
var list = GetListAsync();
var count = GetCountAsync();
return Task.WhenAll(list, count).ContinueWith(_ => new Type2
{
List = list.Result,
Count = count.Result,
});
}
修改
如评论中所建议,最好只使用await
。我还建议阅读由GSerg-Performance of Task.ContinueWith in non-async method vs. using async/await
答案 2 :(得分:0)
问题是Task.WhenAll
方法不接受具有不同结果类型的任务。所有任务必须是同一类型。幸运的是,这很容易解决。 WhenAll
变体下面将等待两个具有不同类型的任务,并返回具有合并结果的任务。
public static Task<TResult> WhenAll<T1, T2, TResult>(
Task<T1> task1, Task<T2> task2, Func<T1, T2, TResult> factory)
{
return Task.WhenAll(task1, task2).ContinueWith(t =>
{
var tcs = new TaskCompletionSource<TResult>();
if (t.IsFaulted)
{
tcs.SetException(t.Exception.InnerExceptions);
}
else if (t.IsCanceled)
{
tcs.SetCanceled();
}
else
{
tcs.SetResult(factory(task1.Result, task2.Result));
}
return tcs.Task;
}, default, TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default).Unwrap();
}
可以这样使用:
public Task<SomeType> GetAsync()
{
return WhenAll(GetListAsync(), GetCountAsync(),
(list, count) => new SomeType { List = list, Count = count });
}
相对于其他解决方案的优势在于处理异常。如果GetListAsync
和GetCountAsync
均失败,则从GetAsync
返回的任务会将两个异常都保留在浅AggregateException
中(而不嵌套在另一个AggregateException
中)。>
此答案的灵感来自斯蒂芬·克莱里(Stephen Cleary)的答案here。