【问题标题】:Keeping track of variable instances跟踪变量实例
【发布时间】:2015-11-15 23:07:52
【问题描述】:

下面我创建了一个名为promiseRipple 的函数,它接收一个对象字面量,其值是函数。每个函数可以包含同步代码或异步promise

var _ = require('lodash')
var Promise = require('bluebird')

function promiseRipple (start, props) {
  props = (props) ? props : start
  start = (props) ? start : {}
  props = _.mapValues(props, function (prop, key) {
    prop.key = key
    return prop
  })
  return Promise.reduce(_.values(props), function (result, action) {
    if (typeof action !== 'function') throw new Error('property values must be functions')
    return Promise.resolve(action(start)).then(function (value) {
      start[action.key] = value
      return value
    })
  }, null)
  .then(function () {
    return start
  })
}

这是基本用法

promiseRipple({zero: 'zero'}, {
  'alpha': function (data) {
    return Promise.resolve(data.zero + ' alpha') // async -> 'zero alpha'
  },
  'beta': function (data) {
    return data.zero + ' beta' // -> 'zero beta'
  },
  'gamma': function (data) {
    return Promise.resolve(data.zero + ' gamma') // async -> 'zero gamma'
  },
  'delta': function (data) {
    return Promise.resolve(data.zero + data.alpha + ' delta') // async -> 'zerozero alpha delta'
  },
}).then(function (results){
  // results -> {
  //   zero: 'zero',
  //   alpha: 'zero alpha',
  //   beta: 'zero beta',
  //   gamma: 'zero gamma',
  //   delta: 'zerozero alpha delta' 
  // }
})

我想添加一些功能,以便每当在函数中返回 data 时,新的数据属性将扩展到现有的。

promiseRipple({zero: 'zero'}, {
  'alpha': function (data) {
    return Promise.resolve(data.zero + ' alpha') // async -> 'zero alpha'
  },
  'beta': function (data) {
    data.foo = data.zero + ' foo' // -> 'zero foo'
    data.bar = data.zero + ' bar' // -> 'zero bar'
    return data
  },
  'gamma': function (data) {
    return Promise.resolve(data.zero + ' gamma') // async -> 'zero gamma'
  },
  'delta': function (data) {
    return Promise.resolve(data.zero + data.alpha + ' delta') // async -> 'zerozero alpha delta'
  },
}).then(function (results){
  // results -> {
  //   zero: 'zero',
  //   alpha: 'zero alpha',
  //   foo: 'zero foo',
  //   bar: 'zero bar',
  //   gamma: 'zero gamma',
  //   delta: 'zerozero alpha delta' 
  // }
})

我尝试创建一个自定义对象字面量,让我能够检测 prop 函数的返回值是 data 还是某个新变量。但是这不起作用。

var _ = require('lodash')
var Promise = require('bluebird')

function Start (data) {
  if (data) return data
  return {}
}
Start.prototype = Object.prototype

function promiseRipple (start, props) {
  props = (props) ? props : start
  start = (props) ? new Start(start) : new Start()
  props = _.mapValues(props, function (prop, key) {
    prop.key = key
    return prop
  })
  return Promise.reduce(_.values(props), function (result, action) {
    if (typeof action !== 'function') throw new Error('property values must be functions')
    return Promise.resolve(action(start)).then(function (value) {
      console.log(value instanceof Start)
      if (value instanceof Start) {
        _.extend(start, value)
        return start
      } else {
        start[action.key] = value
        return value
      }
    })
  }, null)
  .then(function () {
    return start
  })
}

module.exports = promiseRipple

有什么好的方法可以检测返回的对象是否与我们开始使用的对象相同,而不会弄乱对象的值?

【问题讨论】:

  • 这里没有什么是异步的。这只是为了演示目的吗?如果不是这样,删除所有这些承诺会让一切变得更简单。
  • 问题毫无意义。所有关于数据和承诺的细节都与实际提出的问题无关。如果您不相信函数不会弄乱对象,请不要传递它。而是传递一个(深度)克隆。
  • 不要这样做。对象本质上是无序的。您不能依赖任何应该执行函数的特定顺序。
  • @Bergi 天生无序?还是不慎下令?是的,有时您无法保证订单。但是对于控制流,我相信这很好。查看async, does the same thing。我添加了一些代码来替代上面的涟漪,这是灾难性的。我相信在控制流和对象创建方面这是一个可行的选择。
  • @ThomasReggi:是的,async.js 也有同样的问题。是的,对象本质上是无序的,这对于控制流尤其重要。对于(更好的)替代方案,请查看 How do I access previous promise results in a .then() chain? 和 Bluebird 的 Promise.props(如果您真的想创建一个对象)

标签: javascript function oop promise


【解决方案1】:

由于它与您提出问题的动机有关,您应该注意,在 JavaScript 中,非原始变量是“通过引用”传递给函数的。这意味着函数内对象的更改在函数外被引用时会反映在对象中,如果传回则无关紧要。

要回答您的问题,您只需检查对象和返回值是否相等。

注意:

function f(obj) {
    obj.b = 'b test';
    return obj;
}

var obj_1 = {};
obj_1.a = 'a test';
// This is really just a reference to the same object as obj_1
var obj_2 = f(obj_1);

console.log(obj_1); // {a: "a test", b: "b test"}
console.log(obj_2); // {a: "a test", b: "b test"}
// Here is how you can test for equality with the original object passed in
console.log(obj_1 === obj_2); // true

【讨论】:

  • 这太棒了,是的,它是同一个对象变量,所以我可以检查start === value 是否返回value 不需要clone。这太棒了,我想多了。
  • 乐于助人!如果这回答了您的问题,请务必标记它。 :)
猜你喜欢
  • 2015-05-24
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-31
相关资源
最近更新 更多