对象类型变量的闭包

时间:2016-07-04 04:01:53

标签: javascript node.js promise closures

略微修改之前的question,我的确切用例低于我传递对象的位置,在这种情况下,最佳解决方案是什么?

Product.prototype.list = function(body) {
    body.options = {
        hostname: endPoints.product,
        path: '/applications/' + body.entity.type,
        method: 'GET'
    };
    return remote.request(body)
        .then(function(result){
            body[body.entity.type] = result;
            return body;
        });
};

var body = {
    entity: {
        type: null
    }
};

body.entity.type = "coke";
product.list(body)
    .then(console.log); //will this have {coke: []} or {pepsi: []}

body.entity.type = "pepsi";
product.list(body)
    .then(console.log);

当我使用基于对象的引用时它没有工作,在这种情况下解决方案是什么?

2 个答案:

答案 0 :(得分:0)

您的问题是代码是异步的。因此,正在发生的事情是这样的:

  1. 您设置了body.entity.type =“coke”

  2. 您进行异步通话

  3. 您设置了body.entity.type =“pepsi”

  4. 您进行另一次异步通话

  5. 解释器处于空闲状态(不再运行javascript)    因此它可以执行网络代码。

  6. Javascript首先发出网络请求 with body.entity.type =“pepsi”

  7. Javascript发出第二个网络请求 with body.entity.type =“pepsi”

  8. 网络请求已完成(可能是顺序可能不是,具体取决于 (首先到达)并调用回调。

  9. 因此,两个console.log都会有“pepsi”,因为对象是引用,而你将同一个对象传递给两个请求。

    IS 可以使用普通对象:

    var body1 = {
        entity: {
            type: "coke"
        }
    };
    
    var body2 = {
        entity: {
            type: "pepsi"
        }
    };
    
    product.list(body1)
        .then(console.log);
    
    product.list(body2)
        .then(console.log);
    

    如果要使代码更可重用,请使用构造函数:

    function Body (type) {
        this.entity = {type: type};
    }
    
    product.list(new Body('pepsi'))
        .then(console.log);
    
    product.list(new Body('coke'))
        .then(console.log);
    

    或者使用返回对象文字的函数:

    function makeBody (type) {
        return {entity: {type: type}};
    }
    
    product.list(makeBody('pepsi'))
        .then(console.log);
    
    product.list(makeBody('coke'))
        .then(console.log);
    

    单个对象的全局引用与函数内创建的对象之间的区别在于前者只是在将来等待发生的两个事件之间共享的一个对象,后者是两个单独的对象传递给两个单独的事件

答案 1 :(得分:0)

由于您正在使用承诺和异步操作,因此两个异步操作同时"在飞行中"

并且,在Javascript对象中通过指针传递(而不是通过复制)。因此,如果将对象传递给异步操作并且异步操作将使用/修改该对象,然后将同一对象传递给另一个将要同时使用它的异步操作,那么您将尝试两个异步操作使用相同的对象。

因此,根据两个异步操作的个别时序,您将得到不可预测的结果。无论哪个异步操作最后完成,都会对对象进行最后一次修改,覆盖之前完成的对象。

这里通常的解决方案是不将同一个对象传递给异步操作或更改异步操作,以便它们自己创建传入的对象副本,然后修改副本并返回该副本。只要您将不同的对象传递给每个异步操作或更改异步操作,这样他们就不会修改传入的对象,那么您将避免这种冲突。

总结一下,有两种可能的解决方案:

  1. 不要将同一个对象传递给每个异步操作。为每个异步调用创建一个新对象。
  2. 更改您的异步操作,以便他们不会修改传入的对象(他们可以创建并返回自己的对象)。