typescript 在打字稿中链接承诺
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38764277/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Chaining Promises in Typescript
提问by jayars
How do I convert async/await code (Typescript + es6 target)
to using chained Promise.then()
?
如何将 async/await 代码转换(Typescript + es6 target)
为使用 chained Promise.then()
?
For example:
例如:
function mockDelay<T>(getValue:()=>T): Promise<T> {
return new Promise<T>(resolve=>setTimeout(()=>resolve(getValue()), 10));
}
// Assume blackbox implementation
class Service {
constructor(private i=1, private callCount=0){}
opA() : Promise<number> {
this.callCount++;
return mockDelay(()=>this.i+=1);
}
opB(value:number) : Promise<number> {
this.callCount++;
return mockDelay(()=>this.i+=value);
}
opC(): Promise<number> {
return mockDelay(()=>this.i+=2);
}
isA(): Promise<boolean> { return mockDelay(()=>this.callCount%2===0); }
isC(): Promise<boolean> { return mockDelay(() =>true); }
}
// Convert this async/await code to using chained Promises
async function asyncVersion(): Promise<string[]>{
let expected:string[] = [];
let lib = new Service();
let sum = 20;
let lastValue = 0;
while (sum > 0) {
expected.push(`${sum} left`);
if (await lib.isA())
{
expected.push("Do A()");
lastValue = await lib.opA();
sum -= lastValue;
}
else
{
expected.push("Do B()");
lastValue = await lib.opB(lastValue);
sum -= lastValue*3;
if (await lib.isC()) {
expected.push("Do C()");
sum += await lib.opC();
}
}
}
expected.push("All completed!");
return expected;
};
function chainPromiseVersion(): Promise<string[]>{
// How to convert the asyncVersion() to using chained promises?
return Promise.resolve([]);
}
// Compare results
// Currently running asyncVersion() twice to ensure call results are consistent/no side effects
// Replace asyncVersion() with chainPromiseVersion()
Promise.all([asyncVersion(), asyncVersion() /*chainPromiseVersion()*/])
.then(result =>{
let expected = result[0];
let actual = result[1];
if (expected.length !== actual.length)
throw new Error(`Length: expected ${expected.length} but was ${actual.length}`);
for(let i=0; i<expected.length; i++) {
if (expected[i] !== actual[i]){
throw new Error(`Expected ${expected[i]} but was ${actual[i]}`);
}
}
})
.then(()=>console.log("Test completed"))
.catch(e => console.log("Error: " + e));
I know I can transpile es6 code to es5 using Babel (Github example).
我知道我可以使用 Babel(Github 示例)将es6 代码转换为 es5 。
This question is about manually rewriting async/await code to using chained promises.
这个问题是关于手动重写异步/等待代码以使用链式承诺。
I can convert simple examples like the following.
我可以转换如下简单示例。
// Async/Await
(async function(){
for (let i=0; i<5; i++){
let result = await mockDelay(()=>"Done " + i);
console.log(result);
}
console.log("All done");
})();
// Chained Promises
(function(){
let chain = Promise.resolve(null);
for (let i=0; i<5; i++){
chain = chain
.then(()=>mockDelay(()=>"Done " + i))
.then(result => console.log(result));
}
chain.then(()=>console.log("All done"));
})();
But have no idea how to convert the example above, where:
但是不知道如何转换上面的示例,其中:
- loop condition affected by promise result
- execution must be one-after-the-other (no
Promise.all()
)
- 受承诺结果影响的循环条件
- 执行必须是一个接一个(否
Promise.all()
)
采纳答案by Bergi
await
s become then
calls - often nested ones for scoping and control flow to be effective - and loops become recursion. In your case:
await
s 变成then
调用——通常是嵌套的,用于范围和控制流有效——循环变成递归。在你的情况下:
(function loop(lib, sum, lastValue){
if (sum > 0) {
console.log(`${sum} left`);
return lib.isA().then(res => {
if (res) {
console.log("Do A()");
return lib.opA().then(lastValue => {
sum -= lastValue;
return loop(lib, sum, lastValue);
});
} else {
console.log("Do B()");
return lib.opB(lastValue).then(lastValue => {
sum -= lastValue*3;
return lib.isC().then(res => {
if (res) {
console.log("Do C()");
return lib.opC().then(res => {
sum += res;
return loop(lib, sum, lastValue);
});
}
return loop(lib, sum, lastValue);
});
});
}
});
} else {
console.log("All completed!");
return Promise.resolve()
}
})(new Service(), 20, 0);
Luckily you had no form of break
/continue
/return
inside your loop, as that would've made it even more complicated. In general, convert all statements to continuation passing style, then you can defer them where necessary.
幸运的是,您的循环中没有break
/ continue
/形式return
,因为这会使它变得更加复杂。通常,将所有语句转换为连续传递样式,然后您可以在必要时推迟它们。
回答by jayars
Thanks to Bergi's answer, I think I've figured out how to do a step-by-step conversion from async/await to chained promise
.
感谢 Bergi 的回答,我想我已经找到了从 async/await 到 chained 的逐步转换的方法promise
。
I've created a helper function promiseWhile
to help myself:
我创建了一个辅助函数promiseWhile
来帮助自己:
// Potential issue: recursion could lead to stackoverflow
function promiseWhile(condition:()=>boolean, loopBody: ()=>Promise<any>): Promise<any> {
if (condition()) {
return loopBody().then(()=>promiseWhile(condition, loopBody));
} else {
// Loop terminated
return null;
}
}
The steps I've used:
我使用的步骤:
- Whenever
await op()
is hit, convert toreturn op().then(()=>{...})
- where
{...}
is the code after theawait
(including assignment from await)
- where
- This results in some deep nesting, but if I follow these steps, I find myself less likely to make a mistake
- Once completed and verified, I can then go in and clean things up
- 每当
await op()
被击中时,转换为return op().then(()=>{...})
{...}
后面的代码在哪里await
(包括等待的赋值)
- 这会导致一些深度嵌套,但如果我按照这些步骤,我发现自己不太可能犯错
- 完成并验证后,我就可以进去清理东西了
// Converted
function chainPromiseVersion(): Promise<string[]>{
let expected:string[] = [];
let lib = new Service();
let sum = 20;
let lastValue = 0;
return promiseWhile(
// Loop condition
()=>sum>0,
// Loop body
()=> {
expected.push(`${sum} left`);
return Promise.resolve(null)
.then(()=>lib.isA())
.then(isA => {
if (isA) {
expected.push("Do A()");
return lib.opA()
.then(v =>{
lastValue = v;
sum -= lastValue;
});
}
else {
expected.push("Do B()");
return lib.opB(lastValue)
.then(v=>{
lastValue = v;
sum -= lastValue*3;
return lib.isC().then(isC => {
if (isC) {
expected.push("Do C()");
return lib.opC().then(v => {
sum += v;
});
}
});
});
}
}) // if (lib.isA())
}) // End loop body
.then(()=>expected.push("All completed!"))
.then(()=>expected);
}