【问题标题】:Promise chaining not working. Why?承诺链不起作用。为什么?
【发布时间】:2013-05-17 04:31:25
【问题描述】:

我有以下代码来选择多个联系人,并且只过滤具有 XYZ 的名称。我正在使用然后完成这个过滤器。在我的联系人中,有一位名为 XYZ Dude 的联系人,我也在选择它。在我在 then 方法中应用过滤逻辑之后,不应该在我的 done 方法中传递这个联系人吗?任何想法我在这里可能做错了什么

var picker = new Windows.ApplicationModel.Contacts.ContactPicker();

        // Open the picker for the user to select a contact.
        picker.pickMultipleContactsAsync().then(function (contacts) {
            var contactsStartingWithPrefixPa = contacts.filter(function filterContacts(contact) {
                if (contact.name.match(/XYZ/))
                    return true;
                return false;
            });
        }).done(function (contacts) {
            // code never reaches here
            if (contacts != null ) {
                contacts.forEach(function (contact) {
                    if (contact !== null) {
                        // logic to use this contact

                    }
                }
            )}
        });

【问题讨论】:

    标签: javascript windows-8 windows-runtime winjs promise


    【解决方案1】:

    return contactsStartingWithPrefixPa 在 then 函数中是必需的。

       // Open the picker for the user to select a contact.
        picker.pickMultipleContactsAsync().then(function (contacts) {
            var contactsStartingWithPrefixPa = contacts.filter(function filterContacts(contact) {
                if (contact.name.match(/XYZ/))
                    return true;
                return false;
            return contactsStartingWithPrefixPa;
            });
    

    【讨论】:

      【解决方案2】:

      除非有充分的理由将过滤器与“使用此联系人的逻辑”分开,否则两者都可以在一个循环操作中执行。

      var picker = new Windows.ApplicationModel.Contacts.ContactPicker();
      
      // Open the picker for the user to select a contact.
      picker.pickMultipleContactsAsync().done(function(contacts) {
          if(contacts) {
              contacts.forEach(function(contact) {
                  if(contact.name.match(/XYZ/)) {
                      // logic to use this contact
                  }
              });
          }
      });
      

      否则,您将使用.filter() 循环遍历contacts,然后使用.forEach() 再次循环。

      如果你真的必须分离两个方面,那么(假设contacts 有一个.filter() 方法)你应该可以这样做:

      var picker = new Windows.ApplicationModel.Contacts.ContactPicker();
      
      // Open the picker for the user to select a contact.
      picker.pickMultipleContactsAsync().then(function(contacts) {
          return contacts ? contacts.filter(function(contact) {
              return !!contact.name.match(/XYZ/);
          }) : [];
      }).done(function(contacts) {
          contacts.forEach(function(contact) {
              // logic to use this contact
          });
      });
      

      【讨论】:

        【解决方案3】:

        contacts.filter 的返回值不是一个承诺,所以你不需要在这里做任何额外的链接。您的代码应如下所示,因为 contactsStartingWithPrefixPa 只是联系人的投影,因此您可以直接进行 forEach 迭代:

                picker.pickMultipleContactsAsync().done(function (contacts) {
                var contactsStartingWithPrefixPa = contacts.filter(function filterContacts(contact) {
                    if (contact.name.match(/XYZ/))
                        return true;
                    return false;
                })
        
                if (contactsStartingWithPrefixPa.length > 0) {
                    contactsStartingWithPrefixPa.forEach(function (contact) {
                        //Process
                    });
                }
            });
        

        只有当链的每一步(最后一步除外)都返回一个新的 Promise 时,Promise 的链式才有效。如果没有返回的承诺,你就没有另一个异步步骤,所以你可以直接处理你需要的东西

        【讨论】:

        • 如果一个 promise 上的回调函数返回一个 non-promise,它会被基础设施自动包装在该值的 promise 中。所以严格来说,你必须有另一个承诺才能进行链接。不过,你应该返回一些东西,否则你会得到一个未定义的承诺。
        • 感谢您的澄清,克里斯。最终总是需要另一个 Promise,但知道非 Promise 将被自动包装这一事实很有帮助。
        • 是的,我也不知道,听起来如果你不期待它会产生一些奇怪的结果。与其简单地返回myObj 并让它自动包装,不如明确地返回WinJS.Promise.as( myObj )
        猜你喜欢
        • 2022-01-15
        • 1970-01-01
        • 2021-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-09
        • 2017-04-29
        • 1970-01-01
        相关资源
        最近更新 更多