如何在Object值的异步for循环完成执行后调用函数

时间:2014-02-20 23:09:00

标签: javascript ajax node.js asynchronous

我想在异步for循环之后调用一个函数,迭代Javascript对象的值完成执行。我有以下代码

for (course in courses) {
    var url = '...' + courses[course];

    request(url, (function (course) {
        return function (err, resp, body) {
            $ = cheerio.load(body);

            //Some code for which I use object values    
        };
    })(course));
}

2 个答案:

答案 0 :(得分:6)

这可以在vanilla JS中完成,但我推荐使用async模块,这是用于处理Node.js中异步代码的最流行的库。例如,使用async.each

var async = require('async');

var courseIds = Object.keys(courses);

// Function for handling each course.
function perCourse(courseId, callback) {
    var course = courses[courseId];

    // do something with each course.
    callback();
}

async.each(courseIds, perCourse, function (err) {
    // Executed after each course has been processed.
});

如果要使用每次迭代的结果,则async.map类似,但将结果数组传递给回调的第二个参数。

如果您更喜欢vanilla JS,那么这将取代async.each

function each(list, func, callback) {
    // Avoid emptying the original list.
    var listCopy = list.slice(0);

    // Consumes the list an element at a time from the left.
    // If you are concerned with overhead in using the shift
    // you can accomplish the same with an iterator.
    function doOne(err) {
        if (err) {
            return callback(err);
        }

        if (listCopy.length === 0) {
            return callback();
        }

        var thisElem = listCopy.shift();

        func(thisElem, doOne);
    }

    doOne();
}

(摘自gist我写了一段时间)

我强烈建议您使用异步库。 Async很难编写,像async.auto这样的函数很棒。

答案 1 :(得分:2)

一个可能的简单JS解决方案就是做这样的事情。

var courses = {
  lorum: 'fee',
  ipsum: 'fy',
  selum: 'foe'
};

var keys = Object.keys(courses);
var waiting = keys.length;

function completedAll() {
  console.log('completed all');
}

function callOnCourseComplete(course, func) {
  console.log('completed', course);
  waiting -= 1;
  if (!waiting) {
    func();
  }
}

var delay = 10000;
keys.forEach(function(course) {
  var url = '...' + courses[course];
  console.log('request', url);
  setTimeout((function(closureCourse) {
    return function( /* err, resp, body */ ) {
      // Some code for which I use object values
      callOnCourseComplete(closureCourse, completedAll);
    };
  }(course)), (delay /= 2));
});

更新:可能更好的Javascript解决方案是使用Promise s

const courses = {
  lorum: 'fee',
  ipsum: 'fy',
  selum: 'foe',
};

function completedAll() {
  console.log('completed all');
}

function callOnCourseComplete(courseName) {
  console.log('completed', courseName);
}

let delay = 10000;
const arrayOfPromises = Object.keys(courses).map(courseName => (
    new Promise((resolve, reject) => {
      const url = `...${courses[courseName]}`;
      console.log('request', url);
      setTimeout((err, resp, body) => {
        if (err) {
          reject(err);
        }

        // Some code for which I use object values
        resolve(courseName);
      }, (delay /= 2));
    }))
  .then(callOnCourseComplete));

Promise.all(arrayOfPromises)
  .then(completedAll)
  .catch(console.error);