【问题标题】:How to execute asynchronous code in Javascript如何在Javascript中执行异步代码
【发布时间】:2021-10-05 18:27:56
【问题描述】:

我查看了 MDN 网络文档 article 关于异步函数,但由于某种原因它对我不起作用

这是我的代码

function createObject() {
        try {
      console.log("Processing POST Loan.");
    
        var data = {
            "value1" : 1288,
            "value2" : [{
                "value3" : 3833,
                    "value4": [{
                        "value5": new Date()
                    }]
            }]      
        }
        var auth = Buffer.from("login:pass").toString('base64')
        const res = request("http://url.com/resource", {
          method: "POST",
          headers: {
            'Content-Type': 'application/json',
            'Authorization': "Basic "+auth
          },
          body: JSON.stringify(data)
      }, function(error, response, body){
            //console.log(response + ' '+body)
      })
      var response = res.body.id;
      return response
   }
   catch(err) { 

    throw err
    }
}

async function uploadReport() {
    console.log('cerate object')
    var objectId = await createObject();
    console.log('object = '+objectId)
}
 uploadReport() 

与文章中描述的完全一样。但是当我运行我的脚本时,我得到了这个结果:

cerate object
Processing POST Loan.
'data {"value1":1288,"value2":[{"value3":3833,"value4":[{"value5":"2021-10-05T09:45:46.126Z"}]}]}'
'auth '
object = undefined

然后几秒钟没有任何反应,执行停止。 Http 请求工作正常,并且在我运行脚本时正在创建对象,尽管我没有得到任何响应(此 API 应返回自动生成的对象 ID)。我在这里做错了什么?

【问题讨论】:

    标签: javascript node.js async-await


    【解决方案1】:

    我假设您是 JS 编程的新手,并且您似乎对异步代码的执行流程如何工作缺乏了解。

    在 JS 中,异步代码在 Promise 中工作。 Promises 是 JS 表示代码的方式,最终会产生一个值(或 void,但它是一样的)。

    所以现在我们需要一种方法来控制执行流程。这意味着,我们应该能够在获得该结果之后执行依赖于该结果的代码。或者换句话说,我们应该等待 promise 解决,然后执行依赖它的代码。

    输入回调。回调是在 JS 中完成的(在 async/await 出现之前,但我们不要超前)。由于函数是 JS 中的一等公民,我们可以声明它们并将它们作为函数参数传递。因此,在这些术语中,回调是应在 Promise 为我们提供结果后执行的代码。

    谈到回调,我个人见过两种处理方法。

    第一种方法,函数期望这样的回调作为参数。 通常(但不一定是这样)第一个参数是执行任务所必需的实际参数,最后一个是回调:要做什么任务完成后做。示例:

    // A function that receives an `arguments` object and a `callback` function.
    // Observe 
    function doSomethingAsynchronous(arguments, callback) {
      const a = arguments.a
      const b = arguments.b
    
      const result = a + b //this is not asynchronous, only to illustrate.
    
      callback(result)
    }
    

    你可以这样使用这个函数:

    doSomethingAsynchronous({a:2, b:3}, (result)=>{
      console.log(`The result was ${result}`)
    })
    

    注意doSomethingAsynchronous 不返回任何内容;执行流程指向回调。

    第二种方法可能是一个返回实际 Promise 的函数。 Promise 有一个then() 方法和一个catch() 方法。这些用于在 Promise 解析后链接更多代码:

    function iReturnAPromise(arguments) {
      return new Promise((resolve, reject) => {
        const result = arguments.a + arguments.b;
        resolve(result);
    
      })
    }
    

    您将通过这样做来管理执行流程:

    const promiseOfTheResult = iReturnAPromise({a: 2, b:2})
    
    promiseOfTheResult.then((result) => {console.log(result)})
    
    // You'll never see it like that. You'll always see:
    
    iReturnAPromise({a:2, b:3}).then((result) => {console.log(result)})
    

    最后,但同样重要的是,async/await 简化了 Promise 的使用。使用 async await,你会声明 iReturnAPromise 一样,但你会像这样使用它;

    const result = await iReturnAPromise({a:1, b:2})
    
    console.log(result)
    

    请注意最后一种方法如何使代码保持一致并避免回调地狱。还要注意不能等待不返回承诺的函数,它们首先必须被“承诺”:即将它们包装在承诺中。

    【讨论】:

    • 感谢您的回复和非常有帮助的解释!但是,您能否也查看我的评论以获得第一个回复?似乎我无法访问已解析对象的属性,尽管当我打印出整个对象时,属性值存在
    • 不客气!恐怕你这次提到的问题似乎与不同的东西有关。我的建议是,如果您设法通过异步代码,您将帮助您的答案标记为正确并打开另一个与“我可以记录属性并查看它,但无法访问它”问题相关的问题。不过,顺便说一句,我会说调试将是找到问题的最快方法:)
    【解决方案2】:

    我们从头开始吧,因为你似乎有点困惑。

    您要做的是从callback 类型的函数(“请求”)进行异步调用。为此,您必须使用Promise

    所以你的 createObject 函数必须返回一个新的 Promise 对象,或者必须声明为 async 函数。在您的情况下,由于 request 函数使用回调模式,因此您必须使用 Promise 对象,因为它将为您提供一个回调,当您的 Promise 解决时必须调用该回调。

    
    function createObject() {
        return new Promise((resolve, reject) => {
            try {
                 console.log("Processing POST Loan.");
        
                 var data = {
                    "value1" : 1288,
                    "value2" : [{
                        "value3" : 3833,
                            "value4": [{
                                "value5": new Date()
                            }]
                    }]      
                 }
               var auth = Buffer.from("login:pass").toString('base64')
               const res = request("http://url.com/resource", {
                   method: "POST",
                   headers: {
                       'Content-Type': 'application/json',
                       'Authorization': "Basic "+auth
                   },
                   body: JSON.stringify(data)
               }, function(error, response, body){
                   if(error) reject(error);
                   resolve({ response, body });
               });
           }
           catch(err) { 
               reject(err);//the promise is rejected
           }
        });
    }
    
    async function uploadReport() {
        console.log('cerate object')
        const res = await createObject();
        //in res you get 'response' and 'body' where you have the result of your API.
        //it's up to you to adapt this to what you want
        console.log(res);
    }
    
    uploadReport() 
    
    

    【讨论】:

    • 这有效,但是当我尝试解决返回的对象 id 时它仍然未定义? const res = await createObject(); var objectId = res.body.id console.dir(objectId) 虽然响应存在并且我可以在其中看到“id”属性
    猜你喜欢
    • 1970-01-01
    • 2013-01-16
    • 2016-12-08
    • 2017-09-25
    • 2019-02-09
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    相关资源
    最近更新 更多