如何在javascript中使用异步函数分配对象值

时间:2017-04-16 03:18:31

标签: javascript object asynchronous

我正在构建一个javascript对象,其中一些值由异步函数定义。我的问题是对象定义得比异步函数返回值更快:

    const array = ['a', 'b', 'c', 'd']
    const myArrayObj = [];

    function returnKey1 () {
        // make async call then store it in the return key1val:
        return key1val
    }

    function returnKey2 () {
        // make async call then store it in the return key2val:
        return key2val
    }

    function returnKey3 () {
        // make async call then store it in the return key3val:
        return key3val
    }

    _.forEach( array, function ( arr ) {
        myArrayObj.push({
            key1: returnKey1(), // returns undefined
            key2: returnKey2(), // returns undefined
            key3: returnKey3(), // returns undefined
      });

    });

有谁知道我应该这样做的正确方法?提前致谢!

3 个答案:

答案 0 :(得分:2)

异步性的本质是,如果要访问其最终结果,必须等待异步过程完成。

在你的情况下,你可以使用承诺而不是很多代码来实现这一点。:

// promise that resolves after 2 seconds
const timeoutPromise = (str) => new Promise(resolve => setTimeout(() => resolve(str), 2000));

// functions that return promises that will eventually resolve to appropriate key values 

function returnKey1() {
  return timeoutPromise('key3');
}

function returnKey2() {
  return timeoutPromise('key2');
}

function returnKey3() {
  return timeoutPromise('key3');
}

// helper function that returns a promise which will resolve with all the keys when all key-returning promises resolve

function getKeys() {
  return Promise.all([
    returnKey1(),
    returnKey2(),
    returnKey3()
  ])
}

// usage
getKeys().then((keys) => {
  console.log(
    keys[0],
    keys[1],
    keys[2]
  );
});

老派的方法是使用回调而不是承诺,这些承诺具有更大的浏览器支持但是更加粗糙和原始。

注意:使用现代转换器和/或promise库,您也可以获得对承诺的广泛浏览器支持。

// function that calls its callback after 2 seconds
const timeoutCallback = (cb, key) => setTimeout(() => cb(key), 2000);

// functions that eventually call their callbacks with appropriate key values 

function returnKey1(cb) {
  return timeoutCallback(cb, 'key1');
}

function returnKey2(cb) {
  return timeoutCallback(cb, 'key2');
}

function returnKey3(cb) {
  return timeoutCallback(cb, 'key3');
}

// helper function that calls its callback when all the keys are obtained

function getKeys(cb) {
  let keys = [undefined, undefined, undefined];
  let hasAllKeys = () => keys.every(key => typeof key === 'string');

  function makeReturnKeyCallback(idx) {
    return (key) => {
      keys[idx] = key;
      if (hasAllKeys()) {
        cb(keys);
      }
    };
  }

  returnKey1(makeReturnKeyCallback(0));
  returnKey2(makeReturnKeyCallback(1));
  returnKey3(makeReturnKeyCallback(2));
}

// usage
getKeys((keys) => {
  console.log(
    keys[0],
    keys[1],
    keys[2]
  );
});

答案 1 :(得分:1)

无论你做什么都将最终使用承诺。您可以直接使用Promise.all,或者如果您愿意花费更多时间,可以为对象编写自己的Promise.all版本;最后,您可以使用async函数执行此操作,这是一种以类似于同步的方式编写基于承诺的代码的方法。

使用Promise.all

// Just examples for testing purposes.
function returnKey1() { return promise(); }
function returnKey2() { return promise(); }
function returnKey3() { return promise(); }

// Make a promise returning a random value after random time.
function promise() {
  return new Promise(resolve => {
    const random = Math.random() * 1000;
    setTimeout(() => resolve(random), random);
  });
}

// Wait for all promises to finish, then construct result.
Promise.all([returnKey1(), returnKey2(), returnKey3()])
  .then(([key1, key2, key3]) => ({key1, key2, key3}))
  .then(console.log);

为对象

编写自己的Promise.all版本

我们还可以为对象创建模拟Promise.all。有些图书馆有这样的例程。我们将其称为promiseAllKeys。我们将传递一个对象,其中每个属性值都在promise中;它返回一个包含所有值的对象的承诺。这样就省去了将从Promise.all返回的数组转换为所需对象的麻烦。

function returnKey1() { return promise(); }
function returnKey2() { return promise(); }
function returnKey3() { return promise(); }

function promise() {
  return new Promise(resolve => {
    const random = Math.random() * 1000;
    setTimeout(() => resolve(random), random);
  });
}

// Convenience routine to construct an object from arrays of keys and values.
function objectFromKeysAndValues(keys, values) {
  const result = {};
  for (const i = 0; i < keys.length; i++) result[keys[i]] = values[i];
  return result;
}
 
function promiseAllKeys(promises) {
  return Promise.all(Object.values(promises))
    .then(values => objectFromKeysAndValues(Object.keys(promises), values));
}

promiseAllKeys({key1: returnKey1(), key2: returnKey2(), key3: returnKey3()})
  .then(console.log);
    

使用async/await

您可以使用异步功能简化代码。但是,编写的代码将等到每个promise完成后再运行下一个。

function returnKey1() { return promise(); }
function returnKey2() { return promise(); }
function returnKey3() { return promise(); }

function promise() {
  return new Promise(resolve => {
    const random = Math.random() * 1000;
    setTimeout(() => resolve(random), random);
  });
}

async function makeObject() {
  return {key1: await returnKey1(), key2: await returnKey2(), key3: await returnKey3()};
}

makeObject().then(console.log);

答案 2 :(得分:0)

简单而凌乱:

const array = ['a', 'b', 'c', 'd']
const myArrayObj = [];

function returnKey1 (cb) {
    // make async call then store it in the return key1val:
    cb ("key1val");
}

function returnKey2 (cb) {
    // make async call then store it in the return key2val:
   cb("key2val");
}

function returnKey3 (cb) {
    // make async call then store it in the return key3val:
    cb("key3val");
}

_.forEach( array, function ( arr ) {
    var o ={};

    returnKey1(function(key){
        o.key1=key;
      returnKey2(function(key){
        o.key2=key;
        returnKey3(function(key){
            o.key3=key
          myArrayObj.push(obj);
        })
      })
    })

  });

});