typescript async函数必需返回promise么

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了typescript async函数必需返回promise么相关的知识,希望对你有一定的参考价值。

1.promise

promise模式在任何时刻都处于以下三种状态之一:未完成(unfulfilled)、已完成(resolved)和拒绝(rejected)。以CommonJS Promise/A 标准为例,promise对象上的then方法负责添加针对已完成和拒绝状态下的处理函数。then方法会返回另一个promise对象,以便于形成promise管道,这种返回promise对象的方式能够支持开发人员把异步操作串联起来,如then(resolvedHandler, rejectedHandler); 。resolvedHandler 回调函数在promise对象进入完成状态时会触发,并传递结果;rejectedHandler函数会在拒绝状态下调用。(其中rejectedHandler可选)。

以下为一个有几级嵌套的函数,看起来比较令人恶心。(如果换成缩进四个字符可想而知)

\'use strict\'; const md = require(\'markdown-it\')(); const fs = require(\'fs\'); fs.watchFile(\'nodejs.md\', (curr, prev) => let mdStr = fs.readFile(\'./nodejs.md\', \'utf-8\', (err, data) => let mdData = md.render(data); let htmlTemplate = fs.readFile(\'./index.html\', \'utf-8\', (err, data) => let html = data.replace(\'content\', mdData); console.log(mdData); fs.writeFile(\'./nodejs.html\', html, \'utf-8\', (err, data) => if (err) throw err; else console.log(\'OK\'); ); ); ); );

一下用promise的方式实现同样的效果,首先把异步函数封装一下,然后下面可以指教调用。可能看起来代码比之前的版本更多,但是封装的异步函数是可以复用的。等任务多了就不显得代码多了。(但看最后调用函数的部分是不是优雅了不少)
参考技术A 确实需要返回Promise对象,但是这里的返回指的是函数返回类型,而函数内部的return 可以是其他类型。例如async fn(): Promise<string> return '111'

为啥 Typescript 认为 async/await 返回包装在承诺中的值?

【中文标题】为啥 Typescript 认为 async/await 返回包装在承诺中的值?【英文标题】:Why does Typescript think async/await returns a value wrapped in a promise?为什么 Typescript 认为 async/await 返回包装在承诺中的值? 【发布时间】:2018-03-29 15:07:14 【问题描述】:

我想将一个 Promise 链重构为 async/await,但 Typescript 抱怨打字。

TS2322:类型“IHttpPromiseCallbackArg”不可分配给类型“IResp”...

我认为await 会返回一个常规值,而不是一个承诺。我错了吗?如果是这样,我如何分配类型以便编译所需的代码?

我认为 await 会返回与 .then 回调中的第一个参数相同的值。我错了吗?

旧代码:

handleSubmit(form) 
    const params = this.getParams(form);

    this.myAsyncRequest(params)
       .then((resp:IResp) => this.processResp(resp))
       .catch((e:IServerError) => this.handleError(e));
 

所需的新代码:

async handleSubmit(form) 
    const params = this.getParams(form);

    try 
        const resp:IResp = await this.myAsyncRequest(params); //typing error with "const resp:IResp"
        this.processResp(resp);
     catch (e:IServerError) 
        this.handleError(e);
    

如果我删除 myAsyncRequest 中的返回类型,所需的代码仍然会中断;我猜 Typescript 直接从 AngularJS 库中推断出来的。

myAsyncRequest(params:IParams):IHttpPromise<IResp> 
    return $http.post('blah', data);

如果我从 const resp 声明中删除“IResp”,则 processResponse 会抱怨 IHttp 不等于 IResp...

processResp(resp:IResp) 
    //do stuff

【问题讨论】:

IHttpPromiseCallbackArg 类型不是承诺。这已经是函数调用的实际结果了。见definitelytyped.org/docs/angular-translate--angular-translate/… 我可以将我的问题改写为 - “我认为 await 会返回与 .then 回调中的第一个参数相同的值。我错了吗?” 你是对的。但是你对 then 回调函数中第一个参数的类型是错误的。见definitelytyped.org/docs/angularjs--angular-route/interfaces/… 也许您对实际使用的类型定义错误。但是我们需要一个完整的工作示例来明确地说明这一点。 【参考方案1】:

包含await 的行确实等待解析的值 - 但由于函数本身是异步的(允许所有等待),你会得到一个承诺。

示例...在下面的代码中,您可以将x 用作纯数字(即使delay 返回一个承诺)并再次用于y - 因此您等待的所有内容都已解决,因此您可以使用如果它是同步的,它更像你会的。

看起来不像它的异步函数返回了一个承诺,现在可以了。

这似乎令人困惑,因为它似乎“颠倒了承诺”,但它所做的是将then 转移到顶层(您可以让异步函数调用其他异步函数等等)。

function delay(ms: number) 
    return new Promise<number>(function(resolve) 
        setTimeout(() => 
            resolve(5);
        , ms);
    );



async function asyncAwait() 
    let x = await delay(1000);
    console.log(x);

    let y = await delay(1000);
    console.log(y);

    return 'Done';


asyncAwait().then((result) => console.log(result));

【讨论】:

所以说到底,我还是得在某个地方打电话给.then 可能仍然必须在最顶部调用then(在某些情况下,您将函数传递给其他东西,您不必这样做) . 反对票是怎么回事?有什么改进答案的建议吗? 这并没有回答似乎对函数返回的类型有误解的问题。 IHttpPromiseCallbackArg 类型不是提问者所假设的承诺。 我试图回答“我认为 await 会返回一个常规值,而不是一个承诺。我错了吗?”【参考方案2】:

您的问题“我认为 await 会返回与 .then 回调中的第一个参数相同的值。我错了吗?”。

不,你完全正确。但是您对 .then 回调中的第一个参数是错误的。

您将myAsyncRequest 定义为返回IHttpPromise&lt;IResp&gt;。但是IHttpPromise&lt;T&gt;被定义为继承IPromise,方式如下:

type IHttpPromise<T> = IPromise<IHttpPromiseCallbackArg<T>>;

因此,IHttpPromise&lt;T&gt; 是一个返回 IHttpPromiseCallbackArg&lt;T&gt; 的承诺,其中 T 类型的实际数据位于 dataIHttpPromiseCallbackArg&lt;T&gt; 属性中。

所以,我们在问题中看到的旧代码变体:

handleSubmit(form) 
    const params = this.getParams(form);

    this.myAsyncRequest(params)
       .then((resp:IResp) => this.processResp(resp))
       .catch((e:IServerError) => this.handleError(e));
 

myAsyncRequest 被定义为返回 IHttpPromise 时,实际上不应该在 TypeScript 中正确编译。

如何解决这个问题:

async handleSubmit(form) 
    const params = this.getParams(form);

    try 
        const httpResp:IHttpPromiseCallbackArg<IResp> = await this.myAsyncRequest(params); 
        const resp: IResp = httpResp.data;
        this.processResp(resp);
     catch (e:IServerError) 
        this.handleError(e);
    


注意:在最新的 Angular 类型定义中,IHttpPromiseCallbackArg&lt;T&gt; 类型实际上称为IHttpResponse&lt;T&gt;

也许在您的代码中,您已将IResp 定义为IHttpResponse&lt;Something&gt;?那么你只是与旧名称IHttpPromiseCallbackArg 发生冲突。然后从DefinitelyTyped 获取使用新名称的最新类型定义。您还必须将myAsyncRequest 的定义更改为:

myAsyncRequest(params:IParams):IHttpPromise<Something> 

【讨论】:

以上是关于typescript async函数必需返回promise么的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript:用于在 setTimeout() 中返回异步函数调用的类型?

typeScript函数篇

Typescript async/await 无法确定正确的返回类型

async/await 在名为“then”的类方法中

如何在 Node+Typescript+VSCode 中查找 Async 函数调用中缺少的 Await?

如何使用 Typescript 在 Vue 3.0 setup() 函数中使用 async/await