我正在构建一个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
});
});
有谁知道我应该这样做的正确方法?提前致谢!
答案 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);
})
})
})
});
});