首页 > 解决方案 > 迭代通常适用于 Map()、Set().. 但会违反承诺

问题描述

步骤提供重现..

const map = new Map()
let success = new Set()

let failed = new Set()
map.set('success', success)
map.set('failed', failed)
success.add(123)
failed.add(55)
success.add(456)

var iter = map.entries()
console.log(
  'printing map output ==> ',
  map,
  'map.entries() ==> ',
  map.entries(),
  'iter.next().value ==> ',
  iter.next().value,
  'iter.next().value ==> ',
  iter.next().value
)

for (const [key, value] of map.entries()) {
  for (const val of value) {
    console.log(key, val)
  }
}

上面的代码输出我以下预期的结果..

结果没有承诺


所以现在,我使用同样的代码和一个 promise,

$(button).submit(updateTags(enteredTags, tagName,contentIDs).then(
  (resultMap) => {
     console.log("result after promise ==> ", resultMap); // I get proper output here, please see the below image for this

       for (const [key, value] of resultMap.entries()) {
           for (const val of value) {
               console.log("key ==> ", key,"value ==> ", val)// I don't get all the results here.. I am hurting my head with this, did I do any mistake ?
           }
       }
  }));


  let updateTags = (newTags, tagName, contentIds) => {
    let deferred = Q.defer(),
        resultMap = new Map(),
        success_ids = [],
        failed_ids = [],
        counter = 1;
    resultMap.set("success", success_ids);
    resultMap.set("failed", failed_ids);

     contentIds.forEach(function (contentId) {
        var tags = [];
        osapi.jive.core.get({
            v: "v3",
            href: "/contents/" + contentId + ""
        }).execute(function (content) {
            tags = content.tags;
            content["tags"] = _.union(tags, newTags);
            osapi.jive.core.put({
                v: "v3",
                href: "/contents/" + contentId + "",
                body: content
            }).execute(function (response) {
                    if (response.error) {
                        failed_ids.push(contentId);
                    } else {
                        success_ids.push(contentId);
                    }
                    if (counter === contentIds.length) {
                        deferred.resolve(resultMap);
                        $("#spinner").hide()
                    }
                    counter++;
                    deferred.resolve(resultMap);
                }, function (error) {
                    failed_ids.push(contentId);
                    if (counter === contentIds.length) {
                        deferred.resolve(resultMap);
                        $("#spinner").hide()
                    }
                    counter++;
                }
            );
        })
    });
    return deferred.promise;
};

此代码的输出图像如下: 有希望的结果

最后,第二个代码片段“with promise”应该显示如下结果: 在此处输入图像描述

我现在已经添加了我的所有代码,promise 只解析一次,我得到 resultMap 来检查成功和失败的 ID。我想迭代它们以再次将它们转储到记录器中。

标签: javascriptdictionaryecmascript-6promiseset

解决方案


在您问题中当前的代码中,您过早地解决了承诺:

let updateTags = (newTags, tagName, contentIds) => {
     //... removed some code that does not show where you go wrong
     contentIds.forEach(function (contentId) {
        osapi.jive.core.get()
        .execute(function (content) {
            }).execute(function (response) {
                    if (response.error) {
                        failed_ids.push(contentId);
                    } else {
                        success_ids.push(contentId);
                    }
                    if (counter === contentIds.length) {
                        deferred.resolve(resultMap);
                        $("#spinner").hide()
                    }
                    counter++;
                    //here you are always resolving the promise
                    deferred.resolve(resultMap);

我认为以下应该有效:

let updateTags = (newTags, tagName, contentIds) => {
    let deferred = Q.defer(),
        resultMap = new Map(),
        success_ids = [],
        failed_ids = [],
        counter = 1;
    resultMap.set("success", success_ids);
    resultMap.set("failed", failed_ids);
    //promise will never be resolved if you have no content ids
    if(contentIds.length === 0){
      //not sure if Q.resolve exist but here you return a resolved
      //  promise with the empty success and failed arrays
      $("#spinner").hide();
      return Promise.resolve(resultMap);//resolve with empty value
    }

     contentIds.forEach(function (contentId) {
        var tags = [];
        osapi.jive.core.get({
            v: "v3",
            href: "/contents/" + contentId + ""
        }).execute(function (content) {
            tags = content.tags;
            content["tags"] = _.union(tags, newTags);
            osapi.jive.core.put({
                v: "v3",
                href: "/contents/" + contentId + "",
                body: content
            }).execute(function (response) {
                    counter++;
                    if (response.error) {
                        failed_ids.push(contentId);
                    } else {
                        success_ids.push(contentId);
                    }
                    if (counter === contentIds.length) {
                        deferred.resolve(resultMap);
                        $("#spinner").hide()
                    }
                }, function (error) {
                    //I assume execute will either call one or the other function
                    // that is passed to it so increment counter here
                    counter++;
                    failed_ids.push(contentId);
                    if (counter === contentIds.length) {
                        deferred.resolve(resultMap);
                        $("#spinner").hide()
                    }
                }
            );
        })
    });
    return deferred.promise;
};

推荐阅读