繁体   English   中英

在承诺和异步函数中使用for..in循环

[英]Using for..in loop with Promises and asynchronous functions

我需要能够遍历图像的一个对象,并且一次对每个图像执行一个异步功能。 如果将图像对象转换为数组,则可以正常工作,但是我想使用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结束调用。 我只是无法理解,有人可以帮忙吗?

使用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")) 

另一方面,如果您的异步函数返回了自己的诺言,那么这看起来会容易一些:

 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")) 

如果还需要访问键,则只需使用Object.keysObject.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 setTimeout内部; 这使它更易于使用,并且您需要传递的回调更少。

让您将real for … in循环的替代方法是async / await语法:

(async function loop() {
  for (const key in images)
    await asynchronousImageFunction(key, images[key]);
  console.log("end");
})();

实际上,您将无法使用for...in来进行此操作。 不能指示for...infor...offor...in循环在开始下一次迭代之前要等待异步事件。

您所要做的是实现一些行为,该行为的行为类似于所需的循环,但确实要等待异步事件。 您所做的工作就像一个数组的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的文档。

您会发现我在这里没有使用Promise。 这主要是因为您的asynchronousImageFunction功能以及async库本身都是基于回调的。 在处理异步代码时,我的建议是尽量不要在样式之间来回切换,否则东西会令人困惑。

如果您能够使CommonJS模块在您的环境中工作,那么可以使用基于承诺的async变体。 我的最爱之一在这里 有了它,您可以使循环本身基于承诺:

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');
    });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM