蓝鸟承诺和别名

时间:2016-03-26 19:55:57

标签: javascript promise bluebird

有没有办法传递promises数组,以便您可以通过给定的别名而不是索引来访问结果?不使用道具。

喜欢这样的事情:

var a = [{shop: promise(customer)},{customer:promise(customer)}]

Promise.all(a).then(function(res){
    console.log(res.shop):
});

道具可以用于此,但它不符合我的要求,但这里是如何使用道具完成如果有人需要它:

Promise.props({
    pictures: getPictures(),
    comments: getComments(),
    tweets: getTweets()
}).then(function(result) {
    console.log(result.tweets, result.pictures, result.comments);
});

2 个答案:

答案 0 :(得分:3)

Promise.all()仅适用于数组,但使用ES6:

const a = [promise(customer), promise(customer)];
Promise.all(a)
  .then(([shop, customer]) => console.log(shop))

或者,使用Bluebird的Promise.prototype.spread()

var a = [promise(customer), promise(customer)];
Promise.all(a)
  .spread(function(shop, customer) {
    console.log(shop);
  });

答案 1 :(得分:0)

您可以创建自己的.all()版本,以满足您的要求:

Promise.allProp = function(arrayOfObjects) {
    var promises, keys = [];
    arrayOfObjects.forEach(function(item) {
        var key = Object.keys(item)[0];      // use first property only
        promises.push(item[key]);
        keys.push(key);
    });
    return Promise.all(promises).then(function(results) {
        // combine results array back with keys
        var obj = {};
        return results.forEach(function(r, index) {
            obj[keys[index]] = r;
        })
        return obj;
    });
}

你传递了一个像

这样的对象数组
[{shop:  funcAPromise()}, {customer: funcAPromise()}]

并且,生成的promise的解析值将是一个对象,每个属性名称都有一个结果。

{shop:  funcAResolvedValue, customer: funcBResolvedValue}

用法:

var array = [{shop:  funcAPromise()}, {customer: funcAPromise()}];
Promise.allWithProps(array).then(function(results) {
   console.log(results);   // {shop:  funcAResolvedValue, customer: funcBResolvedValue}
});

或者,如果您已经使用Bluebird,按下输入数组以适应Promise.props()想要的内容并直接使用它可能更容易:

Promise.allProp = function(arrayOfObjects) {
    var obj = {};
    arrayOfObjects.forEach(function(item) {
        var key = Object.keys(item)[0];
        obj[key] = item[key];
    });
    return Promise.props(obj);
}

如果您无法扩展Promise对象并且已经拥有Bluebird,那么您可以创建一个帮助函数来将您的对象数组修改为Promise.props()想要的单个对象:

 function convertToObject(array) {
    var obj = {};
    array.forEach(function(item) {
        var key = Object.keys(item)[0];
        obj[key] = item[key];
    });
    return obj;
 }

 Promise.props(convertToObject(myInputArrayOfObjects)).then(function(r) {
     console.log(r.tweets);
     console.log(r.comments);
 });

注意:这些解决方案都假设您不会对同一属性名称拥有多个承诺,并且每个传入对象只有一个属性名称。如果有多个具有相同属性名称的对象,则行为略有不同。

第一个Promise.allProp()实际上将等待所有承诺,但只返回最后一个的解析结果。

第二个Promise.allProp()convertToObject()解决方案只会等待最后一个冲突的承诺,如果有任何冲突并返回最后解决的结果。

如果需要,可以更改前两个解决方案中的任何一个以包含传入对象(而不仅仅是第一个属性)上的所有属性。

更多通用实施

这是一个更通用的解决方案,对输入属性冲突进行错误检查。这适用于通用的ES6承诺,并取代Bluebird的Promise.props()功能,因为这将接受具有属性列表的单个对象或每个都具有属性列表的对象数组。

它将处理所有对象上的所有属性/值对。如果它看到给定的属性名称出现在多个对象上,它将抛出一个异常 - 它们必须都是唯一的,因为这是在具有属性/值对的单个对象中传回结果的唯一方法,其中value是传入承诺的已解决价值。

这是更通用的实现。

// Takes a single object or an array of objects 
//   where each object has one or more keys/value pairs
// The values are all promises which should be combined and waited on with Promise.all()
// The keys must all be unique across all the objects in the array,
//   the same key cannot appear in any other object
// The resolved value is a single object with key/value pairs where the value is the
//     resolved value of all the incoming promises
Promise.allProp = function(obj) {
    try {
        var arrOfObjErr = "Must pass an object or array of objects to .allProp()";
        if (typeof obj !== "object") {
            throw new Error(arrOfObjErr);
        }
        // if just a single object was passed, then put it in an array so the general array processing code works
        var arr = Array.isArray(obj) ? obj : [obj];
        var promises = [], keys = [], keyMap = {};
        arr.forEach(function(item) {
            if (typeof item !== "object") {
                throw new Error(arrOfObjErr);
            }
            Object.keys(item).forEach(function(key) {
                if (keyMap[key]) {
                    throw new Error("Conflicting property name '" + key + "' - all property names must be unique");
                } else {
                    // show key has already been used
                    keyMap[key] = true;
                    // save promise and key in separate arrays
                    promises.push(item[key]);
                    keys.push(key);
                }
            });
        });
    } catch(e) {
        // turn any synchronous exceptions into a rejection so the caller doesn't have to use try/catch
        return Promise.reject(e);
    }
    // await all promises, then combine resolved results with original keys into a single object
    return Promise.all(promises).then(function(results) {
        // combine results array back with keys
        var obj = {};
        results.forEach(function(result, index) {
            obj[keys[index]] = result;
        })
        // resolve with a single object full of key/value pairs
        return obj;
    });
}

在实现中,它遍历传入的所有对象,并收集单独的promises数组和相应的键数组。使用Promise.all()等待promises数组,然后当这些promise完成后,它会将每个promise的解析结果处理回具有原始属性名称的对象。最终解析的结果是一个具有属性/值对的单个对象。

如果找到任何冲突的密钥,它将拒绝提供描述性错误消息。

// example of single object
Promise.allProp({tweets: p1, comments: p2}).then(function(result) {
    console.log(result.tweets);
    console.log(result.comments);
}, function(err) {
    console.log(err);
});

// example of array of objects
Promise.allProp([{tweets: p1, comments: p2}, {pictures: p3}]).then(function(result) {
    console.log(result.tweets);
    console.log(result.comments);
    console.log(result.pictures);
}, function(err) {
    console.log(err);
});

// example of illegal same property appearing on more than one object
Promise.allProp([{tweets: p1, comments: p2}, {tweets: p3, pictures: p4}, ]).then(function(result) {
    console.log(result.tweets);
    console.log(result.comments);
    console.log(result.pictures);
}, function(err) {
    // will reject because of "tweets" property appearing on more than one object
    console.log(err);
});

代码的测试用例:https://jsfiddle.net/jfriend00/uamxax4e/