如何在 TypeScript 中使用 async/await 和 jQuery 的 $.post() 方法

22

我的异步函数中的await语句调用了jQuery的$.post()方法,该方法返回一个有效的promise,然而在TypeScript中我遇到了这个错误:

“await”操作数的类型必须是一个有效的promise,或者不能包含一个可调用的“then”成员。

我的函数如下(为了示例简化了代码)。代码是有效的并且可以工作,但是我在TS控制台中遇到了一个错误。

 async function doAsyncPost() {
    const postUrl = 'some/url/';
    const postData = {name: 'foo', value: 'bar'};
    let postResult;
    let upateResult;

    function failed(message: string, body?: string) {
      console.log('error: ', message, ' body: ', body);
    }

    function promiseFunc() {
      return new Promise<void>( resolve => {
        // ... do something else....
        resolve();
      });
    };

    function finish() {
      // ... do something at the end...
    }

    try {
      // The error is on the $.post()
      postResult = await $.post(postUrl, $.param(postData));
      if (postResult.success !== 'true') {
        return failed('Error as occoured', 'Description.....');
      }      
      await promiseFunc();

      return finish();
    } catch (e) {
      await failed('Error as occoured', 'Description.....');
    }
  }

我猜 TS 在使用 $.post() 时遇到了问题,因为你可以对其调用 .then(),但该如何解决这个问题呢?此外,在更新至 2.4.2 之前我没有遇到这个错误。


看起来TypeScript确实对jQuery返回的同时是Promise对象和jqXHR对象很麻烦。尝试 postResult = await Promise.resolve($.post(postUrl, $.param(postData))); 或者,另一种选择是:postResult = await $.post(postUrl, $.param(postData)).then(); 尽管后者可能会触发相同的错误。 - trincot
@trincot 你提供的两个解决方案都可以。看起来有点不太干净和不必要,但目前为止是最好的选择了。如果你想把你的评论作为答案提供,我会标记它为已接受。 - Amir
2个回答

31

看起来 TypeScript 对于 jQuery 返回一个既是 deferred 又是 jqXHR 对象的 promise 对象确实有些棘手:

自 jQuery 1.5 版本以来,$.ajax()返回的 jqXHR 对象实现了 Promise 接口,使它们具有 Promise 的所有属性、方法和行为(有关更多信息,请参见 Deferred 对象 )。

至少有三种解决 TypeScript 这种顽固性的方法

返回纯 ES6 Promise 的解决方案

你可以将返回值传递给Promise.resolve(),它将返回一个真正的 ES6 Promise,承诺相同的值:

postResult = await Promise.resolve($.post(postUrl, $.param(postData)));

返回jQuery promises的解决方案

另外两种方法并非返回纯ES6 promises, 而是返回jQuery promises,这已经足够好了。需要注意的是,这些promise对象只有从jQuery 3开始才符合Promise/A+规范

您可以使用deferred.promise 方法,它返回一个jQuery promise对象:

postResult = await $.post(postUrl, $.param(postData)).promise();

或者,您可以应用deferred.then方法,该方法还返回一个jQuery Promise:

从jQuery 1.8开始,deferred.then()方法返回一个新的Promise对象。

如果未向then提供任何参数,则将有效地返回相同承诺值的Promise对象:

postResult = await $.post(postUrl, $.param(postData)).then();

4
$.get(...).then() 对我无效,但 $.get(...).promise() 可以正常工作,并且更易读。 - kitsu.eb
感谢提醒,@kitsu.eb,我已经在我的答案中添加了promise方法的解决方案。在jQuery 1.8之前,then方法是不起作用的,这可能解释了为什么它对你没有起作用。 - trincot

1
JQueryXHR有自己的.then()版本,其中包含一些额外的选项:
then<R>(doneCallback: (data: any, textStatus: string, jqXHR: JQueryXHR) => R, failCallback?: (jqXHR: JQueryXHR, textStatus: string, errorThrown: any) => void): JQueryPromise<R>;

为了在TypeScript中使用$.post的await,我不得不从jquery.d.ts中删除那一行。然后TypeScript将会看到JQueryGenericPromise上定义的.then。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接