我需要能够遍历图像对象并一次一个地对每个图像执行异步功能。
如果我将图像对象转换为数组但是我希望使用 for...in
循环执行此操作,那么我可以使用它,所以我也可以使用图像键。我还需要能够像我目前一样在最后执行一项行动。
var images = {
ABD: '1464685684713583388647.jpg',
ABY: '1457524543088191607099.jpg',
ADV: '1478877365443818880647.jpg',
AFD: '1457527861824290195088.jpg',
}
var imagesArray = Object.values(images);
var len = imagesArray.length;
function asynchronousImageFunction (key, image, onSuccess, onFail) {
setTimeout(function () {
console.log(key);
console.log(image);
onSuccess();
}, Math.random() * 1000)
}
(function loop(i) {
if (i < len) {
new Promise(function (resolve, reject) {
asynchronousImageFunction ('key', imagesArray[i], resolve, reject);
}).then(loop.bind(null, i+1));
} else {
console.log('end');
}
})(0);
订单并不重要,但要让它们一个接一个地调用,并且还需要进行 onComplete 或 end 调用。 我无法理解它,任何人都可以帮忙吗?
答案 0 :(得分:2)
使用reduce
是一种很好的方法。您可以使用Object.entries
var images = {
ABD: '1464685684713583388647.jpg',
ABY: '1457524543088191607099.jpg',
ADV: '1478877365443818880647.jpg',
AFD: '1457527861824290195088.jpg',
}
function asynchronousImageFunction(key, image, onSuccess, onFail) {
setTimeout(function() {
console.log(key);
console.log(image);
onSuccess();
}, 1000)
}
Object.entries(images).reduce((a, [key, value]) => {
return a.then(() => new Promise((resolve, reject) => {
asynchronousImageFunction(key, value, resolve, reject);
}))}, Promise.resolve())
.then(() => console.log("end"))
&#13;
另一方面,如果您的异步函数返回了自己的承诺,那么这对眼睛来说会更容易:
var images = {
ABD: '1464685684713583388647.jpg',
ABY: '1457524543088191607099.jpg',
ADV: '1478877365443818880647.jpg',
AFD: '1457527861824290195088.jpg',
}
function asynchronousImageFunction(key, image, onSuccess, onFail) {
return new Promise((resolve, reject) => {
setTimeout(function() {
console.log(key);
console.log(image);
resolve();
}, 1000)
})
}
Object.entries(images).reduce((a, [key, value]) =>
a.then(() => asynchronousImageFunction(key, value))
, Promise.resolve())
.then(() => console.log("end"))
&#13;
答案 1 :(得分:0)
如果您还需要访问密钥,只需使用Object.keys
或Object.entries
代替Object.values
。
var imageKeysArray = Object.key(images);
var len = imagesArray.length;
(function loop(i) {
if (i < len) {
var key = imageKeysArray[i];
var value = images[key];
asynchronousImageFunction(key, value).then(loop.bind(null, i+1));
} else {
console.log('end');
}
})(0);
请注意,new Promise
包装应该直接围绕setTimeout
调用,位于asynchronousImageFunction
内;这使得它更容易使用,你需要传递较少的回调。
允许您使用真实for … in
循环的替代方法是async
/ await
语法:
(async function loop() {
for (const key in images)
await asynchronousImageFunction(key, images[key]);
console.log("end");
})();
答案 2 :(得分:0)
你真的无法使用for...in
执行此操作。在开始下一次迭代之前,不能指示for...in
和for...of
等循环等待异步事件。
您需要做的是实现与所需循环类似的行为,但 等待异步事件。您所做的事情就像数组上的for...of
一样。您可以通过执行Mark_M描述的操作来使密钥可用。
然而,这是一个非常常见的操作,并且已经在async这样的库中被抽象(以及许多其他异步操作),使您可以跳过这个烦恼并只写下您想要的内容:
var images = {
ABD: '1464685684713583388647.jpg',
ABY: '1457524543088191607099.jpg',
ADV: '1478877365443818880647.jpg',
AFD: '1457527861824290195088.jpg',
}
function asynchronousImageFunction(key, image, callback) {
setTimeout(function () {
console.log(key);
console.log(image);
// Usual convention of `async` callbacks. The first argument should be
// null/undefined/omitted if no error occurred:
callback();
// If there was an error, you would instead do this:
// callback(err);
}, Math.random() * 1000)
}
async.eachOfSeries(images, function(image, key, callback) {
asynchronousImageFunction(key, image, callback);
}, function(err) {
console.log('end');
});
可以找到async.eachOfSeries的文档here。
你会注意到我在这里没有使用Promise。这主要是因为asynchronousImageFunction
是基于回调的,async
库本身也是如此。我在处理异步代码时的建议是不要经常在样式之间来回切换,否则会让hella混淆。
如果您能够在您的环境中使CommonJS模块工作,则存在基于承诺的async
变体。我最喜欢的一个是here。有了它,你可以使循环本身基于承诺:
const pasync = require('pasync');
var images = {
ABD: '1464685684713583388647.jpg',
ABY: '1457524543088191607099.jpg',
ADV: '1478877365443818880647.jpg',
AFD: '1457527861824290195088.jpg',
}
function asynchronousImageFunction(key, image) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(key);
console.log(image);
resolve();
}, Math.random() * 1000);
});
}
pasync.eachOfSeries(
images,
(image, key) => asynchronousImageFunction(key, image)
)
.then(() => {
console.log('end');
});