如何在javascript中使用aynsc/await从异步操作返回对象

如何在javascript中使用aynsc/await从异步操作返回对象,javascript,asynchronous,async-await,ecmascript-2017,Javascript,Asynchronous,Async Await,Ecmascript 2017,我一辈子都搞不懂async/await为什么会这样 考虑这个例子 我想要一个函数,它执行一些数据库初始化,并在完成时返回数据库对象 var globalDb = null; const IDB_DATABASE_NAME = "mydb"; const IDB_STORE_NAME = "mystore"; const IDB_VERSION = 1.0; async function initDb() { var idbOpenDbRequest = window.indexedD

我一辈子都搞不懂async/await为什么会这样

考虑这个例子

我想要一个函数,它执行一些数据库初始化,并在完成时返回数据库对象

var globalDb = null;

const IDB_DATABASE_NAME = "mydb";
const IDB_STORE_NAME = "mystore";
const IDB_VERSION = 1.0;

async function initDb() {
    var idbOpenDbRequest = window.indexedDB.open(IDB_DATABASE_NAME, IDB_VERSION);

    idbOpenDbRequest.onsuccess = function (event) {
            return event.target.result;
    };
}

(async () => {
    globalDb = await initDb();
    console.log("I should happen second")
    console.log(globalDb);
})();
预期
  • log(“我应该先发生”)
  • log(“我应该第二个发生”)
  • 控制台日志(globalDb)//将对象转储到控制台
  • 真实的
  • log(“我应该第二个发生”)
  • 控制台日志(globalDb)//未定义
  • log(“我应该先发生”)
  • 我意识到我基本上误解了一些事情。请告诉我为什么等待不能像我期望的那样起作用。:)

    JSFIDLE


    顺便说一句,忘记这是关于indexedDb的,这个例子非常简单——我认为这与这个问题的主题无关

    所以问题在于
    initDb
    函数。我将为您重新编写,然后解释此版本的工作原理:

    function initDb() {
        var idbOpenDbRequest = window.indexedDB.open(IDB_DATABASE_NAME, IDB_VERSION);
    
        return new Promise((resolve, reject) => {
            idbOpenDbRequest.onsuccess = function (event) {
                setTimeout(function () {
                    console.log("I should happen first");
                    resolve(event.target.result);
                }, 2000);
            };
        })
    }
    
    我所做的是将
    onsuccess
    回调封装在承诺中。Javascript中的异步/等待模式基本上是基于承诺的。要么您自己返回一个承诺,要么它将结果包装成一个承诺(并立即解决它)

    因为您自己没有返回承诺,所以它试图将返回值(未定义)封装在承诺中。然后,它立即解决了导致异步函数返回的问题


    使用此更新的代码,调用initDb,然后返回一个承诺,该承诺只有在建立连接并触发超时后才能得到解决。

    对于异步/等待在这里的工作方式,确实存在一些混淆。我将尝试提供并回答,但同时可能会有所帮助?您正在等待
    initDb()
    ,但您不能等待
    setTimeout
    ,因为它不会返回承诺,因此控制台会意外登录(实际上是预期的)订单和函数返回未定义,因为它没有返回任何内容。@因此他从
    setTimeout
    回调返回内容,并希望它是
    initDb()
    的返回@Kjensen它不是那样工作的。@VaibhavVishal我现在删除了setTimeout,它只是说明了一个关于计时的问题,这太愚蠢了,因为它增加了复杂性(在本例中,实际上把我的示例搞砸了)。基本问题/问题仍然是一样的:为什么函数没有返回任何内容?为什么console.log的顺序与我的预期不同?@Kjensen要从函数中获取某些内容,应该首先返回它。您是否从
    initDb
    ?)返回任何内容),实际上我正在编写相同的内容,但您的速度更快:O)删除
    async
    ,因为在函数中不使用wait关键字是错误的。我将删除
    async
    关键字。@Kjensen您确实可以在使用和不使用
    async
    的情况下使用该函数。我选择在答案中删除它,因为我没有在函数本身中使用
    await
    关键字。@Mathyn,谢谢您提供的解释。这是有道理的