【问题标题】:Async/Await Not Waiting as I expect itAsync/Await 没有像我期望的那样等待
【发布时间】:2019-05-08 11:29:40
【问题描述】:

请多多包涵,我已经投入到一个新项目中,并试图全力以赴。过去几天我一直在取得进展,但似乎无法克服最后的困难。希望我能正确解释。

我正在加载一个 Web 表单,需要调用 API 以获取一些基于当前加载的数据可能存在或不存在的信息。我已经将我的页面简化为基本上是这样的。

...Get some information the user wants and start to do some work to load 
up the page and set up the form.
...old stuff working fine...

//Time for my new stuff
var testValue
async function test() {
    await http.post(appConfig.serviceRootUrl + '/api/XXX/YYY', 
    { mProperty: myObject.collectionInObject.itemInCollection }).then(function (result) {
        if (result.length < 1) {
            testValue= false;
        }
        else if (result[0].infoIWant.trim().length > 0) {
            testValue= true;
        }
    });
}
test(); 

//Originally above in the if I was just seeing if I got a result 
//and setting testValue to true/false but changed it for debugging 
//and I am surely getting back correct values when the data exists 
//or result.length zero when no data for it


...Do a bunch of more stuff that is old and working correctly....

//Test the new stuff up above

 alert(testValue);

大多数时候我会在警报中返回正确的真或假,但有时我会返回未定义。我猜未定义是因为它在异步/等待完成之前到达警报。我的印象是它不会越过我称之为“test();”的那一行。我认为它实际上是让它停止低于 test(); 的任何东西。直到等待结束。最初它有点复杂,但我不断将其剥离以使其(希望)更基本/简单。

我的想法或实施中缺少什么?

非常感谢任何帮助,因为我现在正在追赶我的尾巴。

【问题讨论】:

  • 您需要使用await test()
  • http.post() 来自哪里?如果这是浏览器,那它不是内置在浏览器中的,所以它必须来自某个库。它来自哪个图书馆?它会返回一个承诺吗?

标签: javascript jquery rest promise async-await


【解决方案1】:

这不是异步函数的工作方式。该函数似乎只在函数本身内部等待。在函数外部调用它并同步返回一个promise。

换句话说,如果你写:

 let t = test()

t 将是一个在test() 返回时解决的承诺。在您当前的代码中,如果您想在函数之外做出响应,您需要类似以下内容:

async function test() {
    let result = await http.post(appConfig.serviceRootUrl + '/api/XXX/YYY', 
    { mProperty: myObject.collectionInObject.itemInCollection })
    if (result.length < 1) return false
    else if (result[0].infoIWant.trim().length > 0)  return true;
}


// test is an async function. It returns a promise.
test().then(result => alert("result: " + result ))

基于 cmets 编辑
这是一个使用 Axios 的 http.post 命令的工作版本:

async function test() {
    let result = await axios.post('https://jsonplaceholder.typicode.com/posts', 
    { mProperty: "some val" })
    return result.data
}


// test is an async function. It returns a promise.
test().then(result => console.log(result ))
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 感谢@Mark Meyer,这似乎更干净了,也感谢您的解释。但是,现在它永远不会被调用。什么都没有触发,当我单步执行代码时,“让”行异步块和 test().then 永远不会被触发。想法???
  • 嘿@RichP,不太确定发生了什么。你用什么http.post?您还确定满足if 条件之一吗?我编辑了一个使用 Axios 运行帖子的工作示例。
  • 我注意到在您提出的原始解决方案中, let t = test();它基本上说“t是一个永远不会被调用的承诺”,就像老派一样,你声明了一个变量并且从未使用过它。因此,我将最后一行更改为:'test().then(result =&gt; t = result);,并将警报更改为:alert(" t= " + t);,这在 10 次中有 9 次有效,有几次我得到:` t = [object Promise]`
  • 通过 10 次中的 9 次工作,我的意思是它正确地返回了预期的结果,但偶尔会出现“对象承诺”。与 console.log 相同
【解决方案2】:

这样做怎么样?

...Get some information the user wants and start to do some work to load 
    up the page and set up the form.
    ...old stuff working fine...

    //Time for my new stuff
    var testValue
    async function test() {
       let promise = new Promise( (resolve, reject) => resolve( http.post(appConfig.serviceRootUrl + '/api/XXX/YYY', 
        { mProperty: myObject.collectionInObject.itemInCollection }).then(function (result) {
            if (result.length < 1) {
                testValue= false;
            }
            else if (result[0].infoIWant.trim().length > 0) {
                testValue= true;
            }
        })));
     await promise;
 alert(testValue);
    }
    test(); 

    //Originally above in the if I was just seeing if I got a result 
    //and setting testValue to true/false but changed it for debugging 
    //and I am surely getting back correct values when the data exists 
    //or result.length zero when no data for it


    ...Do a bunch of more stuff that is old and working correctly....

    //Test the new stuff up above

【讨论】:

    【解决方案3】:

    如果你使用.then() 语法,不要await,反之亦然。我对浏览器与 async/await 的兼容性是不正确的,似乎我没有跟上浏览器脚本,而是支持 Node.js。而且,由于您使用的是 jQuery,$.ajax() 对您来说可能是一个不错的选择,因为您不需要 async/await 或 .then(),您可以这样做:

    $.ajax(appConfig.serviceRootUrl + '/api/XXX/YYY', {
        method: 'POST',
        data: { mProperty: myObject.collectionInObject.itemInCollection }
    }).done(function(data) {
        //use result here just as you would normally within the `.then()`
    })
    

    我希望这比我原来的答案更有帮助。

    【讨论】:

    • 我不太喜欢浏览器脚本,除非我使用 react。我已经习惯了不用担心 async/await 是否可用,因为 webpack 会帮我转换成 es5。我不得不承认,我几乎不再了解 es5。稍后我可能会研究哪些浏览器具有它,但现在对我来说,这不是必须的。根据我的经验,我发现最好不要在浏览器中使用 async/await
    • 我希望修复它
    猜你喜欢
    • 2016-12-03
    • 1970-01-01
    • 2018-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 2019-12-04
    相关资源
    最近更新 更多