异步/同步循环Node.js

时间:2016-08-06 16:36:53

标签: javascript node.js asynchronous

嗨,我想尝试做一些有点奇怪的事情,将异步和同步混合在一起,这就是为什么它没有按照我的预期工作。目前从阵列中为3个用户运行然后结束如何在数组中的整个用户名长度运行它?

var i = 0,
fs = require('fs'),
fetch = require('node-fetch');

fs.readFile('file.txt', function(err, data) {
  var array = data.toString().split("\n");
  getCreationDate(array);
});

function getCreationDate(array) {
  fetch('http://mytwitterbirthday.com/api/?screen_name=' + array[i])
  .then(function(res) {
    return res.json();
  }).then(function(json) {
    console.log(i, array[i])
    console.log(json[0].screen_name, json[0].created_at);
  }).then(function() {
    i++;
    getCreationDate(array);
  })
}

3 个答案:

答案 0 :(得分:0)

我假设您不需要按照与阵列相同的顺序打印输出。在这种情况下,您可以更改getCreationDate()以接受单个名称及其索引。

function getCreationDate(name, i) {
  fetch('http://mytwitterbirthday.com/api/?screen_name=' + name)
  .then(function(res) {
    var json = res.json();
    console.log(i, name)
    console.log(json[0].screen_name, json[0].created_at);
  });
}

现在为数组中的每个项调用上面的函数。

array.forEach(getCreationDate);

答案 1 :(得分:0)

可能有助于...... 你错过了一个捕获。

const 
  fs = require('fs'),
  fetch = require('node-fetch')
;

(new Promise((res, rej) => {
  fs.readFile('file.txt', (err, data) => {
    if(err) {
      return rej(err);
    }
    
    return resolve(data.toString().split('\n'));
  });  
}))
  .then(data => doSomething(data, 0))
  .catch(error => console.error.bind(console))
;

function doSomething(data, index) {
  const API = 'http://mytwitterbirthday.com/api/';
  const MAX_ERRORS = 3; // or what you want
  let errors = 0;
  
  return fetch(`${API}?screen_name=${data[index]}`)
    .then(r => r.json())
    .then(response => {
      console.log("response", response);
    })
    .then(() => doSomething(data, ++index))
    .catch(error => {
      if(MAX_ERRORS <= errors) {
        console.log('giving up', {errors});
        return;
      }
      
      errors += 1;
      return doSomething(data, index);
    })
  ;
};

答案 2 :(得分:0)

我会添加另一个答案,因为接受的答案没有提供以下内容:

  1. 完成所有请求后的通知
  2. 按顺序提供结果
  3. 错误处理
  4. 任何并发控制,用于决定同时运行多少请求(对于Twitter速率限制可能很重要)
  5. 第一个解决方案使用Bluebird promise库,因为它显着简化了事情。特别是对于并发控制:

    const Promise = require('bluebird');
    const fs = Promise.promsifyAll(require('fs'));
    const fetch = require('node-fetch);
    
    function getSingleCreationDate(item) {
        return fetch('http://mytwitterbirthday.com/api/?screen_name=' + item).then(function(response) {
            return response.json();
        });
    }
    
    function getAllCreationDates(file) {
        return fs.readFileAsync(file).then(function(data) {
            let array = data.toString().split("\n");
            // put whatever concurrency value here works best, higher is more parallelism
            // lower is more protection from being rate limited by the host
            return Promise.map(array, getSingleCreationDate, {concurrency: 4});
        });
    }
    
    getAllCreationDates('file.txt').then(function(results) {
        // process array of results here (in order)
    }).catch(function(err) {
        // handle error here
    });
    

    此第二个解决方案使用标准ES6承诺并序列化请求,如OP的原始代码:

    const fs = require('fs');
    const fetch = require('node-fetch);
    
    // promisify readFile
    fs.readFileAsync = function(file, options) {
        return new Promise(function(resolve, reject) {
            fs.readFile(file, options, function(err, data) {
                if (err) return reject(err);
                resolve(data);
            });
        });
    }
    
    function getSingleCreationDate(item) {
        return fetch('http://mytwitterbirthday.com/api/?screen_name=' + item).then(function(response) {
            return response.json();
        });
    }
    
    function getAllCreationDates(file) {
        return fs.readFileAsync(file).then(function(data) {
            let array = data.toString().split("\n");
            let results = [];
            return array.reduce(function(p, item) {
                return p.then(function() {
                    return getSingleCreationDate(item).then(function(twitterData) {
                        results.push(twitterData);
                    });
                })
            }, Promise.resolve()).then(function() {
                // make array of results be the resolved value
                return results;
            });
        });
    }
    
    getAllCreationDates('file.txt').then(function(results) {
        // process array of results here (in order)
    }).catch(function(err) {
        // handle error here
    });
    

    或者,如果您同时发送所有请求的Twitter很好,您可以这样做:

    const fs = require('fs');
    const fetch = require('node-fetch);
    
    // promisify readFile
    fs.readFileAsync = function(file, options) {
        return new Promise(function(resolve, reject) {
            fs.readFile(file, options, function(err, data) {
                if (err) return reject(err);
                resolve(data);
            });
        });
    }
    
    function getSingleCreationDate(item) {
        return fetch('http://mytwitterbirthday.com/api/?screen_name=' + item).then(function(response) {
            return response.json();
        });
    }
    
    function getAllCreationDates(file) {
        return fs.readFileAsync(file).then(function(data) {
            let array = data.toString().split("\n");
            return Promise.all(array.map(function(item) {
                return getSingleCreationDate(item);
            }));
        });
    }
    
    getAllCreationDates('file.txt').then(function(results) {
        // process array of results here (in order)
    }).catch(function(err) {
        // handle error here
    });