【问题标题】:Add an undefined method promise to an array to be resolved later in Promise.all()在 Promise.all() 中将未定义的方法 promise 添加到稍后要解析的数组
【发布时间】:2019-06-24 05:00:57
【问题描述】:

我想将连接后将执行的数据库调用排队。 DB 对象在连接时被创建并存储为模块的成员。

数据库模块:

var db = {
  localDb: null,
  connectLocal: (dbName) => {
    // Do stuff
    this.localDb = new PouchDB(dbName) // has a allDocs() method
  }
}

将呼叫添加到队列:

var dbQueue = []

function getDocs () {
  dbQueue.push (
    db.localDb.allDocs () // allDocs() not yet defined; returns promise
  )
}

// Called when connected and queue is not empty:
function processQueue () {
  Promise.all (dbQueue)
  .then(...)
}

如果在 db.connectLocal() 设置 db.localDb 之前调用 getDocs(),则会收到以下错误(或类似错误),因为尚未定义 db.localDb:

TypeError: 无法读取未定义的属性“then”

是否可以将返回一个承诺的未定义方法添加到稍后在 Promise.all() 中解析的数组?关于如何解决此问题的任何其他想法?

另外,我正在使用 Vue.js 和 PouchDB。

【问题讨论】:

  • 为什么getDocs() 甚至在connectLocal() 之前被调用?我认为这是您需要解决的真正问题。
  • 我不知道您的队列在做什么或它应该如何工作(但我怀疑它实际上不起作用)。您能否详细说明您需要什么队列以及在哪里(由谁)调用 getDocsprocessQueue 函数?
  • @Bergi, getDocs() 由于各种原因在多个 Vue 组件中被调用 - 一个组件在 mount() 中调用它,另一个在 onclick 事件之后调用它。我可以检查是否为每个 DB 调用建立了连接,但这会很多,而且一旦建立连接,我仍然需要一种方法来再次调用它。
  • @Bergi,队列中保存着数据库调用,一旦连接数据库就会被处理。它确实有效,但在这种情况下它不起作用,因为我正在添加一个尚未定义的承诺。它是由 Vue.js 组件进行的众多潜在数据库调用之一。我本可以将整个队列部分排除在我的问题之外,因为这不是问题,但我觉得它有助于说明我的问题。
  • 队列部分非常重要,谢谢提及。听起来您在连接后立即调用processQueue,并且不要对数组结构做太多其他事情。然后,我建议删除数组并为您排队的数据库连接使用承诺,就像下面 Marius 的回答一样。然而,如何最好地初始化这个承诺将取决于connectLocal 的调用方式和位置。

标签: javascript asynchronous vue.js promise pouchdb


【解决方案1】:

您可以在您的 db 模块中做出承诺,而不仅仅是 localDb 属性:

let localDb = null;
let resolveLocalDb = null;
let localDbPromise = new Promise(function(resolve, reject) {
    resolveLocalDb = resolve;
});

var db = {
  getLocalDb: () {
    return localDbPromise;
  }
  connectLocal: (dbName) => {
    // Do stuff
    localDb = new PouchDB(dbName) // has a allDocs() method
    resolveLocalDb(localDb);
  }
}

然后,将.localDb 交换为getLocalDb(),这将返回一个承诺。

dbQueue.push(
  db.getLocalDb().then(db => db.allDocs())
)

【讨论】:

  • 你可能只想让属性持有 Promise 本身,而不是 getter 方法。此外,您不需要 localDb 局部变量 - 使用数据库的每个人都将通过 promise 访问该值。
【解决方案2】:

我解决了我的队列问题,但这根本不是我想要解决的问题。

我的第一个问题是认为 Promise.all() 推迟调用我的方法,直到它被调用,但它们在添加到数组时被调用。这导致了我在问题中提到的错误。所以我需要重新考虑如何使用可能尚不存在的方法填充队列。

解决方案是将对数组(队列)的调用添加为字符串(例如"getDocs"),然后循环遍历使用bracket notation 调用方法的数组(例如db["getDocs"]())。

我的应用程序是用 Vue.js 编写的,所以它明显不同,但这里有一个简化的工作示例:

// Dummy DB object
var db = {
  docs: [1, 2, 3]
};

// Queue were the DB ops are stored
var dbQueue = [];

// Process the queue - called elsewhere once the DB is connected
// The processed array and Promise.all() aren't necessary as you could just call
// the method outright, but I want to log the results in order
async function processQueue() {
  var processed = []; // Called queue methods

  // Add valid methods to
  dbQueue.forEach(method => {
    if (typeof db[method] === "function") {
      return processed.push(db[method]());
    } else {
      console.error(`"${method}" is not a name of a valid method.`);
    }
  });

    // Log promise results
  await Promise.all(processed).then(res => {
    console.log("Processed:", res);
  });

  // Empty the queue
  dbQueue = [];
}

// Add some calls to the queue of methods that don't yet exist
dbQueue.push("getDocs");
dbQueue.push("getDocs");

// Simulate adding the method
db.getDocs = function() {
  return new Promise(resolve => {
    resolve(this.docs);
  });
};

// Process queue once conditions are met (e.g. db is connected); called elsewhere
processQueue();

下面是一个允许方法参数的示例:https://jsfiddle.net/rjbv0284/1/

【讨论】:

    猜你喜欢
    • 2020-02-20
    • 2021-01-23
    • 2016-06-21
    • 2018-02-06
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多