如何同步声明JS对象,然后使用依赖于并发操作的数据编辑对象的属性 [英] How to synchronously declare JS object and then edit a property of the object with data that is dependent on a concurrent operation

查看:71
本文介绍了如何同步声明JS对象,然后使用依赖于并发操作的数据编辑对象的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在解析从Eventbrite API返回的数据,并根据事件名称和从整个数据响应中抓取的任何img标签来形成对象。

I'm parsing data returned from Eventbrite's API, and forming objects from the name of the event and any img tags scraped from the entirety of data response.

for (var i = 1, l = rawEventbriteData.length; i < l; i++){

    var eventObject = {
        name: rawEventbriteData[i].event.title,
        images: []
    };

    var jsdom = require('jsdom');
    var arrayOfImgs = [];
    jsdom.env({
        html: rawEventbriteData[i].event.description,
        scripts: ["http://code.jquery.com/jquery.js"],
        done: function(errors, window) {
            window.$('img').each(function(){
                var imgSrc = window.$(this).attr('src');
                console.log(imgSrc);
                eventObject.images.push(imgSrc);
            });
        }
    });

}

我注销结果:

the events are  [ { name: 'Sense 5K - Austin Pre-Registration', images: [] },
  { name: 'Tech Snack - Fostering Student Research', images: [] },
  { name: 'Coffee,Dessert and Chat', images: [] },
  { name: 'Texas Table Tennis!', images: [] },
  { name: '#3and3 w/ @FortyCreek_John', images: [] },
  { name: 'BUSINESS COACHING | CONVERSE-OVER-COFFEE (Austin)',
    images: [] },
  { name: 'Tiny House in Austin, Texas', images: [] },
  { name: 'Fastest House Tour in America', images: [] },
  { name: 'Texas NORML\'s Monthly Open Meeting, Dreadneck Wednesday and Smokin\' Stand-Up',
    images: [] },
  { name: 'Amazing Scavenger Hunt Adventure-Austin', images: [] } ]
https://evbdn.eventbrite.com/s3-s3/eventlogos/90039995/about.png
https://evbdn.eventbrite.com/s3-s3/eventlogos/90039995/bluedawntour1.jpg

我们可以看到每个事件对象都具有预期的name属性,但是图像数组仍然为空。图像源确实会在终端输出的末尾记录日志(在jsdom函数中调用),但是显然这些URL在需要时不可用。

And we can see that the each event object has the name property as expected, but the array of images remains empty. The image sources do end up logging at the end of the terminal output (called within the jsdom function), but clearly these urls are not available when they are needed.

I希望最终获得具有与当前名称相同的名称的eventObjects,以及当前无法及时返回的图像数组。解决此问题的最佳方法是什么?

I want to end up with eventObjects that have the name as they currently do, as well as the array of images that currently doesn't come back in time. What is a good approach for solving this?

推荐答案

这是经典的关闭问题。您作为完成处理函数传递的函数对 eventObject 具有持久引用变量(并且只有一个,它不是特定于循环的),因此仅填写最后一个。(这通常是您想要的,但在这种情况下不是。)

This is the classic closure problem. The function you're passing as the done handler has an enduring reference to the eventObject variable (and there's only one, it's not loop-specific), so only the last one gets filled in. (This is usually what you want, but not in this case.)

您可以使用可关闭其他内容(通常是自变量)的构建器函数来解决此问题:

You can work around it with a builder function that closes over something else (usually an argument):

for (var i = 1, l = rawEventbriteData.length; i < l; i++){

    var eventObject = {
        name: rawEventbriteData[i].event.title,
        images: []
    };

    var jsdom = require('jsdom');
    var arrayOfImgs = [];
    jsdom.env({
        html: rawEventbriteData[i].event.description,
        scripts: ["http://code.jquery.com/jquery.js"],
        done: buildDoneHandler(eventObject)
    });

}

function buildDoneHandler(evtobj) {
    return function(errors, window) {
        window.$('img').each(function(){
            var imgSrc = window.$(this).attr('src');
            console.log(imgSrc);
            evtobj.images.push(imgSrc);
        });
    };
}

请注意, buildDoneHandler返回的函子关闭并使用 evtobj (我们给 buildDoneHanlder 的参数)而不是 eventObject 。由于该参数特定于对 buildDoneHandler 的每次调用,因此我们更新了正确的事件对象。

Note that the functon returned by buildDoneHandler closes over and uses evtobj (the argument we give buildDoneHanlder) rather than eventObject. Since the argument is specific to each call to buildDoneHandler, we update the right event object.

这也可以是使用ES5的 Function#bind 完成,尽管在有其他参数时会引起混淆,并创建了 bind 的函数循环是浪费的(不是通常很重要):

This can also be done with ES5's Function#bind although it can get confusing when there are other arguments, and creating functions that you bind in a loop is wasteful (not that it usually matters):

for (var i = 1, l = rawEventbriteData.length; i < l; i++){

    var eventObject = {
        name: rawEventbriteData[i].event.title,
        images: []
    };

    var jsdom = require('jsdom');
    var arrayOfImgs = [];
    jsdom.env({
        html: rawEventbriteData[i].event.description,
        scripts: ["http://code.jquery.com/jquery.js"],
        done: function(evtobj, errors, window) {
            window.$('img').each(function(){
                var imgSrc = window.$(this).attr('src');
                console.log(imgSrc);
                evtobj.images.push(imgSrc);
            });
        }.bind(null, eventObject)
    });
}

Function#bind 返回一个函数,该函数在被调用时将调用带有特定 this 值的原始函数,并在参数列表的开头提供您提供的其他任何参数。

Function#bind returns a function that, when called, will call the original function with a specific this value and with any further arguments you give it at the beginning of the arguments list.

这篇关于如何同步声明JS对象,然后使用依赖于并发操作的数据编辑对象的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆