Node.JS 中的同步“GET”

Posted

技术标签:

【中文标题】Node.JS 中的同步“GET”【英文标题】:Synchronous "GET" in Node.JS 【发布时间】:2016-08-23 19:06:35 【问题描述】:

我正在尝试遍历 html 块中的图像并获取每个图像的本机宽度。我已经完美地构建了 DOM,并且我在 NPM 上使用 image-size 模块来检索图像宽度。

问题是获取图像并获取它们的宽度需要时间,因此在我恢复宽度之前代码会继续处理。结果,我无法调整 HTML 块中的宽度,因为函数在取回第一张图像之前运行并完成。

在此GET 请求完成之前,是否要停止处理代码?我不希望 For-Loop 继续直到图像完成。

  var elem_tags = doc.getElementsByTagName("img");
  var elem_tags_length = elem_tags.length;

  for (var i=0; i < elem_tags_length; i++) 
    var imgUrl = options.elem_tags[i].getAttribute('src');
    http.get(imgUrl, function (response) 

      // My Code To Manipulate <img> tags
      var chunks = [];
      response.on('data', function (chunk) 
        chunks.push(chunk);
      ).on('end', function() 
        var buffer = Buffer.concat(chunks);
        console.log(imgSize(buffer).width); // imgSize is a module from NPM. Disregard for our loop purposes. 
      );


    );

  

我的完整代码供参考:

var url = require('/usr/lib/node_modules/url');
var http = require('http');
var https = require('https');
var jsdom = require("/usr/lib/node_modules/jsdom").jsdom;
var imgSize = require('/usr/lib/node_modules/image-size/');

var myhtml = '<img src="http://xdesktopwallpapers.com/wp-content/uploads/2011/11-1/Searching-For-Something.jpg" /> <div style="width:500px;border:2px;" id="mytestdiv"><p style="margin:40px;">Harry Potter <img src="https://sites01.lsu.edu/wp/lsupd/files/2011/01/poster1.jpg" style="width:900px" /> and <img  src="http://xdesktopwallpapers.com/wp-content/uploads/2011/11-1/Searching-For-Something.jpg" /> and <img style="width:190px"  src="http://xdesktopwallpapers.com/wp-content/uploads/2011/11-1/Searching-For-Something.jpg" /></p></div>';

function getImage(imgUrl) 
  console.log('image loop');
    return new Promise(function(resolve, reject) 
        http.get(imgUrl, function(err, result) 
            if (err) return reject(err);
            return resolve(result);
        );
    );


var doc = jsdom(myhtml);
var doc = doc.parentWindow.document;    

var elem_tags = doc.getElementsByTagName("img");
var elem_tags_length = elem_tags.length;
var promises = [];

for (var i=0; i < elem_tags_length; i++) 

    var imgUrl = elem_tags[i].getAttribute('src');

    var promise = getImage(imgUrl).then(function(response) 
        // My Code To Manipulate <img> tags .... return promise if async
    );

    promises.push(promise);



Promise.all(promises).then(function() 
    console.log('done');
);

【问题讨论】:

由于不清楚getProtocolVar.get() 方法返回什么,即承诺与否,回调中的一个简单计数器,并检查counter === elem_tags_length 以知道所有图像都已加载是一个选项跨度> 同步代码不是nodejs的编码方式,学习使用回调和promise。 您可以使用async.js 来管理回调和链接。 github.com/caolan/async 使用异步,eachSeries 方法。 @adeneo 很抱歉我忘记更新该代码。它是http 函数。任何想法如何使用承诺。在这种情况下。我对节点很陌生。 【参考方案1】:

创建一个返回承诺的函数,或使用中间件承诺http

function getImage(imgUrl) 
    return new Promise(function(resolve, reject) 
        http.get(imgUrl, function(response) 
            var image = '';

            response.on('data', function(data) 
                image += data;
            );

            response.on('end', function() 
                return resolve(image);
            );

            response.on('error', reject);
        );
    );

然后迭代并存储承诺

var elem_tags = doc.getElementsByTagName("img");
var elem_tags_length = elem_tags.length;
var promises = [];

for (var i=0; i < elem_tags_length; i++) 

    var imgUrl = options.elem_tags[i].getAttribute('src');

    var promise = getImage(imgUrl).then(function(response) 
        // My Code To Manipulate <img> tags .... return promise if async
    );

    promises.push(promise);



Promise.all(promises).then(function() 
    // all done
);

【讨论】:

唯一的细节是你必须等待dataend 事件。见davidwalsh.name/nodejs-http-request 感谢您的建议!我现在正在尝试。 @JuanMendes 我使用 dataend 但这不会阻止此 GET 之外的代码继续。 这里唯一的问题是我需要修改图像标签。因此,一旦for 循环继续,我就无法再返回并更新该图像,因为它完成并输出了“修改后的”HTML(在这种情况下没有改变)。 @DigitalMC 正如 adeneo 指出的那样,创建一个 Promise,其中 cmets 指示返回一个 Promise,在收到 end 事件之前不要解决该承诺 我能想到的Promise.all 不触发的唯一原因是,如果所有的承诺都没有得到解决,你一定是遗漏了什么,或者一个或多个图像没有做他们应该做什么等等。【参考方案2】:

使用异步 eachSeries 方法

async.eachSeries(yourArray, function(item, cb) 
   http.get(imgUrl, function (result) 
    //Do whatever you want with result
    //call the cb function of the async to continue the loop
    cb();

  )
, function()
  //Once your loop is finished, this function will be called
)

【讨论】:

酷,我会试试这些家伙。所以我把http.get(imgUrl, function (response)... 放在yourGetFunction 函数里面? 明白了,这就是我感到困惑的地方。 yourArray 是什么?如何将函数列表存储在数组中还是完全倒退? yourArray 是您拥有的任何数组。在您的情况下,您有一个元素数组。 'elem_tags'。看看这个例子:jsfiddle.net/yLrnrpsc

以上是关于Node.JS 中的同步“GET”的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 同步循环或迭代异步语句

等效于 Node.JS 的 file_get_contents()

Node.js 中的同步 HTTP 请求

为啥使用同步功能 node.js

node.js 中的同步 HTTP 请求

node.js中的forEach是同步还是异步