【问题标题】:How to use promises in javascript如何在 JavaScript 中使用 Promise
【发布时间】:2018-09-28 11:38:32
【问题描述】:

我正在 Cordova 中使用 Typescript 为 Android 制作应用程序,并与 Webpack 捆绑。我不太了解如何在 Javascript 中执行异步任务。我看到了几个关于回调和承诺的教程,但对我来说仍然很困惑,我无法将它调整到我的代码中。我不知道我的问题是来自我的代码本身,还是来自 Typescript/Cordova/Webpack。

我创建了一个函数getAllSMS,它返回一个大对象,并且需要一些时间来执行。我知道该函数有效,因为如果我尝试在检查员的控制台中打印 allSMS 变量,它首先是空的,然后像 1 秒一样填充。 (我认为检查员的行为很奇怪,但确实如此)。

我看到我可以使用 Promise 执行异步任务,但我在理解它的工作原理方面遇到了一些问题。我看过几个教程,但我仍然不明白如何将它应用到我的代码中。

谢谢

[编辑]:这是我的 getAllSMS 函数转换为承诺:

public getAllSMS() {
    return new Promise(//return a promise
        (resolve,reject)=>{
            if (SMS) {
                SMS.listSMS(this.filters, function (data) {
                    resolve(data);//added this, resolve promise
                }, function (err) {
                    console.log('error list sms: ' + err);
                    reject(err);//added this reject promise
                });
            }else{
                resolve([]);//added this, resolving to empty array?
            }
        }
    ).then(
        data=>{
            let contacts = {};
                            for (let key in data) {
                                if ((data[key].address).length > 7 && (data[key].address).match("[0-9]+")) {
                                    let date = SMSManager.convertUnixDate(data[key].date); // on converti le format de date de listSMS
                                    if (contacts.hasOwnProperty(data[key].address)) {
                                        Object.defineProperty(contacts[data[key].address], data[key]._id, {
                                            value: {
                                                "body": data[key].body,
                                                "date": date
                                            }
                                        });
                                    } else {
                                        let myid = String(data[key]._id);
                                        Object.defineProperty(contacts, data[key].address, {
                                            value: {
                                                "000": {
                                                    "body": data[key].body,
                                                    "date": date
                                                }
                                            }
                                        });
                                    }
                                }
                            }
            return contacts;
        }
    );
}

编辑 2:我这样调用我的函数,但我的 for in 循环仍未执行,尽管我的变量似乎已正确加载。

    sms.getAllSMS().then( allSMS => {
        console.log('allSMS');
        console.log(allSMS);
        console.log('then is readed'); // this is readed
        for (let key in allSMS) {
            console.log(allSMS[key]); // this is not executed
        }
    }).catch(
        error => console.warn("something is wrong")
    );

这是控制台的屏幕截图(控制台中的“对象”是 allSMS)。在“对象”旁边有一个小“i”,上面写着:“下面的值刚刚被评估”。

【问题讨论】:

  • 您需要向我们展示getAllSMS 中的代码。里面有些东西需要时间,这就是需要被包装在承诺中的东西。如果您拥有的let allSMS = sms.getAllSMS(); 不起作用,则在调用周围添加一些承诺不会改变有关该功能不起作用的任何内容。
  • mdn doc for then(),它有2个参数。另请参阅Promise.prototype.catch()resolve() 通常不将函数作为参数,您可能希望将那里的代码放入then()。看看一些例子。
  • 在函数 sms.getAllSMS() 中返回新的 promise 并在 then() 中编写函数 getAllSMS
  • 更新的答案,您的 getAllSMS 正在返回一个对象,该对象将来可能会或可能不会变异为有价值的东西。相反,您应该返回一个承诺,以便您知道数据何时可用以及是否可用(无错误)。
  • @Bergi 是的,我误解了如何使用承诺,这就是为什么我试图将它“围绕”该功能。但我知道该函数有效,因为如果我对应该在函数内部返回的变量contact 执行console.log,它就可以工作。如果我尝试在 then 函数中 console.log 它:sms.getAllSMS().then( allSMS => { console.log(allSMS);},它也可以工作。但是for in循环after仍然没有执行。

标签: javascript cordova typescript asynchronous promise


【解决方案1】:

我怀疑 sms.getAllSMS 返回了一个承诺,因此您可以尝试以下操作:

sms.getAllSMS()
.then(
  allSMS => {
    for (let key in allSMS) {
      console.log(allSMS[key]);
    }
  }
)
.catch(
  error=>console.warn("something went wrong, error is:",error)
)

您的 getAllSMS 不返回任何内容,请确保它返回一个承诺:

public getAllSMS(): object {
  return new Promise(//return a promise
    (resolve,reject)=>{
      if (SMS) {
        SMS.listSMS(this.filters, function (data) {
          resolve(data);//added this, resolve promise

        }, function (err) {
          console.log('error list sms: ' + err);
          reject(err);//added this reject promise
        });
      }else{
        resolve([]);//added this, resolving to empty array?
      }
    }
  ).then(
    data=>{
      let contacts = {};
      data.forEach(
        item=>{
          if ((item.address).length > 7 && (item.address).match("[0-9]+")) {
            let date = SMSManager.convertUnixDate(item.date); // on converti le format de date de listSMS
            if (contacts.hasOwnProperty(item.address)) {
              Object.defineProperty(contacts[item.address], item._id, {
                value: {
                  "body": item.body,
                  "date": date
                }
              });
            } else {
              Object.defineProperty(contacts, item.address, {
                value: {
                  "000": {
                    "body": item.body,
                    "date": date
                  }
                }
              });
            }
          };        
        }
      );
      return contacts;
    }
  );
}

【讨论】:

  • 谢谢!但它仍然无法正常工作......我已经编辑了我的帖子。
  • @neiya 您的更新显示 getAllSMS 不返回任何内容,我的答案中的 getAllSMS 返回一个承诺。 dosnt work 也不是很有帮助,在你的问题中使用 sms.getAllSMS().then(...sms.getAllSMS 应该会得到 sms.getAllSMS is not a function 错误。
  • 在我的更新中 getAllSMS() 正在返回一个诺言?按照您的建议,我在函数的开头添加了return new Promise。我在控制台中没有任何错误,for in 循环中的代码只是没有执行,因为我认为当时没有加载对象。我认为我的代码中仍然存在错误,但我找不到在哪里。我在帖子中添加了一些屏幕截图以向您展示控制台。
  • @neiya 是的,我现在看到了更新。似乎您想解析联系人,但正在异步改变它。我已经更新了我的答案,首先获取数据,然后根据数据改变联系人。
  • 我尝试了您的代码并对其进行了一些修改(我在主帖中对其进行了更新),因为我无法对对象执行 forEach。但是当我在对象内部使用 for in 循环执行sms.getAllSMS().then() 时,仍然没有加载。除了 for in 循环之外,我想对该对象执行几项不同的操作,这就是为什么不想将该代码放在 getAllSMS 函数中的原因。
【解决方案2】:

您现在通过使用 Promise 解决了异步问题,看起来不错。

for 循环没有枚举你的属性的问题是Object.defineProperty 确实(默认情况下)创建了不可枚举的属性。改用简单的赋值:

let contacts = {};
for (const key in data) {
    const address = data[key].address;
    if (address.length > 7 && address.match("[0-9]+")) {
        const date = SMSManager.convertUnixDate(data[key].date); // on converti le format de date de listSMS
        const myid = String(data[key]._id);
        if (address in contacts) {
            contacts[address][myid] = {
                "body": data[key].body,
                "date": date
            };
        } else {
            contacts[address] = {
               "000": {
                   "body": data[key].body,
                   "date": date
                }
            }
        }
    }
}
return contacts;

【讨论】:

  • 哦,我明白了,我永远不会想到这一点。谢谢,for in 循环现在可以正常工作了。
猜你喜欢
  • 1970-01-01
  • 2019-08-18
  • 1970-01-01
  • 2013-08-25
  • 2021-08-31
  • 2016-12-18
  • 2021-10-23
  • 1970-01-01
相关资源
最近更新 更多