【问题标题】:Why is my promise's 'resolve' being sent before the functions ends execution?为什么在函数结束执行之前发送我的承诺的“解决”?
【发布时间】:2019-07-19 05:37:05
【问题描述】:

我有一个似乎在我的主代码中异步运行的函数(内部包含承诺,因此它本身同步运行)。无论我如何格式化我的承诺,似乎在函数结束执行之前就发送了解析:

这个问题在逻辑上也是递归的,如果我尝试在 nameExists 函数周围添加另一个 Promise(在这个 Promise 内),然后将 resolve 放在“then”中,我会遇到嵌套 resolve 的相同问题...

    document.getElementById("config-select").addEventListener("input", function(){
      //check if the doc name exists: returns doc id
      //promise that doc_obj is created before moving on
      let doc_obj = {};
      let promise = new Promise(function (resolve, reject) {
        let doc_name = document.getElementById("config-select").value;
        doc_obj = nameExists(doc_name);
        resolve('done'); //this executes BEFORE nameExists is done processing...bringing back the original asynch issue i was trying to fix in the first place...
      });
      promise.then(function (result) {
          alert("then: "+doc_obj);
          if(doc_obj.bool === true){//it does exist:
            alert("replacing id");
            document.getElementById("config-select").setAttribute("doc-id", doc_obj.id);
          }
          else{//it doesn't:
            alert("resetting id");
            document.getElementById("config-select").setAttribute("doc-id", "");
          }
        }
      );

    });

nameExists 函数:

//check if the name in config-select is an existing doc (assumes name is a unique document field)
const nameExists = function(name){
  //get all docs
  localDB.allDocs({include_docs: true}).then(function (result) {
    //return object set to default state if no match is found
    let doc_obj = {bool: false, id: ""};
    alert("Entering the match checker...");

    for(let i =0; i<result.total_rows; i++) {
      if(result.rows[i].doc.name == name){
        alert(result.rows[i].doc.name);
        alert(name);
        doc_obj.bool = true;
        doc_obj.id = result.rows[i].doc._id;
        //found a match
        break;
      }
    }
    //return the result
    alert("returned obj.id: "+doc_obj.bool);
    return doc_obj;

  }).catch(function (err) {console.log(err);});
};

理想情况下,我希望在评估我的“if 语句”之前,用 nameExists 函数的数据填充 doc_obj 或一些返回值对象。如何格式化我的 promise/resolve 语句来实现这一点?

【问题讨论】:

  • 您问题中的承诺没有任何我能辨别的目的。为什么要在 promise 中包含这几行?
  • @Aalok - 你能澄清一下你期望的结果是什么吗?通过阅读您的代码,您似乎正在创建一个承诺,然后立即使用 nameExists 的返回值解决它(您的问题中没有包含该值)。但也许您期待不同的结果?
  • @AalokBorkar 是的,考虑 Promise 是对的,但是您需要使用 Promise inside nameExists 以便它可以为其异步结果返回 Promise。如果您尝试从nameExists 同步返回值,您将始终得到undefined。同样,请发布您的 nameExists 函数的代码,否则我们无法帮助您解决您的问题。另外请务必阅读有关该主题的our canonicalquestions
  • 你的第一句话没有多大意义:“我有一个函数(内部包含承诺,所以它本身同步运行)”。在内部包含 Promise 表明它实际上是异步的,而不是同步的。
  • nameExists 需要返回它的承诺。 return localDB.allDocs(... 那你可以nameExists(...).then(...)

标签: javascript asynchronous promise


【解决方案1】:

你应该放弃那个new Promise - 它不会改变你是否能够等待nameExists'的结果。您将需要 return then()nameExists 函数中创建的承诺:

function nameExists(name) {
  return localDB.allDocs({include_docs: true}).then(function (result) {
//^^^^^^
    for (let i =0; i<result.total_rows; i++) {
      if (result.rows[i].doc.name == name){
        return {bool: true, id: result.rows[i].doc._id};
      }
    }
    return {bool: false, id: ""};
  });
//  ^ don't catch errors here if you cannot handle them and provide a fallback result
}

然后你可以在你的事件监听器中等待它:

document.getElementById("config-select").addEventListener("input", function() {
  const doc_select = document.getElementById("config-select");
  const doc_name = doc_select.value;
  // check if the doc name exists: returns doc id
  nameExists(doc_name).then(function(doc_obj) {
//^^^^^^^^^^^^^^^^^^^^^^^^^^          ^^^^^^^
    console.log("then", doc_obj);
    if (doc_obj.bool) { // it does exist:
      alert("replacing id");
    } else { // it doesn't:
      alert("resetting id");
    }
    doc_select.setAttribute("doc-id", doc_obj.id); // id is "" when it doesn't exist
  }).catch(function (err) {
    console.log(err);
  })
});

【讨论】:

  • 太棒了,你是真正的 Javascript 向导。此实现完美运行,并且我的应用程序的行为完全符合预期。重构也很不错,谢谢 ;)
【解决方案2】:

您拥有的唯一异步调用在 nameExists 函数内部,即数据库调用,因此无需编写两个 Promise,只需一个即可解决您的问题。

第一个事件应该是这样的:

document.getElementById("config-select").addEventListener("input", function(){
   nameExists(doc_name).then(function(doc_obj) {
       alert("then: "+doc_obj);
       if(doc_obj.bool === true){//it does exist:
          alert("replacing id");
          document.getElementById("config-select").setAttribute("doc-id",  doc_obj.id);
       }
       else{//it doesn't:
          alert("resetting id");
          document.getElementById("config-select").setAttribute("doc-id", "");
       }
   }).catch(function (err) { console.log(err) });
});

nameExists 函数应该是这样的:

//check if the name in config-select is an existing doc (assumes name is a unique document field)
const nameExists = function(name){
  //get all docs
  return localDB.allDocs({include_docs: true}).then(function (result) {
    //return object set to default state if no match is found
    let doc_obj = {bool: false, id: ""};
    alert("Entering the match checker...");

    for(let i =0; i<result.total_rows; i++) {
      if(result.rows[i].doc.name == name){
        alert(result.rows[i].doc.name);
        alert(name);
        doc_obj.bool = true;
        doc_obj.id = result.rows[i].doc._id;
        //found a match
        break;
      }
    }
    //return the result
    alert("returned obj.id: "+doc_obj.bool);
    return(doc_obj); // here is where the code runs then statement inside the event

 });      
};

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2020-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多