我有以下代码:
import GtfsRealtimeBindings from 'mta-gtfs-realtime-bindings';
import rp from 'request-promise';
const GetFeedData = (function () {
let feed, feedId;
return {
getFeedId: function (sub) {
switch (sub) {
case '1': case '2': case '3': case '4': case '5': case '6': case 'S':
feedId = 1;
break;
case 'A': case 'C': case 'E':
feedId = 26;
break;
case 'N': case 'Q': case 'R': case 'W':
feedId = 16;
break;
case 'B': case 'D': case 'F': case 'M':
feedId = 21;
break;
case 'L':
feedId = 2;
break;
case 'G':
feedId = 31;
break;
}
},
getFeedData: function () {
rp({
method: 'GET',
url: 'https://cors-anywhere.herokuapp.com/http://datamine.mta.info/mta_esi.php?key=MY_KEY&feed_id=' + feedId,
encoding: null
}).then((buf) => {
feed = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(buf);
});
},
get feed () { return feed; }
};
})();
const ReverseStop = (function () {
let stopIdN, stopIdS;
const stopData = require('./stops');
return {
reverseStop: function (sub, stop) {
function filterByName (item) {
if (item.stop_name == stop && typeof item.stop_id === 'string' && item.stop_id.charAt(0) == sub) {
return true;
}
return false;
}
var stopObjs = stopData.filter(filterByName);
for (var i = 0; i < stopObjs.length; i++) {
if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'N') {
stopIdN = stopObjs[i].stop_id;
} else if (stopObjs[i].stop_id.charAt(stopObjs[i].stop_id.length - 1) == 'S') {
stopIdS = stopObjs[i].stop_id;
}
}
},
stopIdN: stopIdN,
stopIdS: stopIdS
};
})();
export const IsDelayN = (function () {
let noDelay, yesDelay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
(function dataFilter () {
var feedObjs = GetFeedData.feed().entity.filter(function (entityObj) {
if (entityObj.trip_update !== null && entityObj.trip_update.stop_time_update.stop_id == ReverseStop.stopIdN) {
return entityObj.trip_update.stop_time_update;
}
});
for (var i = 0; i < feedObjs.length; i++) {
if (feedObjs.arrival !== undefined) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
})();
var nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
var delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
};
})();
export const IsDelayS = (function () {
let noDelay, yesDelay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
(function dataFilter () {
var feedObjs = GetFeedData.feed().entity.filter(function (entityObj) {
if (entityObj.trip_update !== null && entityObj.trip_update.stop_time_update.stop_id == ReverseStop.stopIdS) {
return entityObj.trip_update.stop_time_update;
}
return false;
});
for (var i = 0; i < feedObjs.length; i++) {
if (feedObjs.arrival !== undefined) {
arrivals.push(feedObjs.arrival.time.low);
delays.push(feedObjs.arrival.delay);
}
}
})();
var nextArrival = Math.min(...arrivals);
var delayIndex = arrivals.indexOf(nextArrival);
var delay = delays.delayIndex;
if (delay === null || Math.ceil(delay / 60) <= 5) {
noDelay = Math.ceil((nextArrival - GetFeedData.feed.header.timestamp.low) / 60);
} else {
yesDelay = Math.ceil(delay / 60);
}
},
noDelay: noDelay,
yesDelay: yesDelay,
};
})();
位于脚本顶部的IIFE末尾的 feed
会返回undefined
,因为request-promise
中的getFeedData
调用是异步的,feed
会返回IIFE顶部的变量在更新之前。我认为我需要做的是将GetFeedData.feed
更改为某种回调(或返回一个承诺)。我不确定该回调应该是什么样的,特别是因为我不认为我可以在该回调中调用getFeedData
,因为这意味着尝试访问同一对象中的对象属性(我非常肯定是禁止的。)
另一件事是,有人告诉我,我需要更改使用 feedback
的代码。这将是dataFilter
IIFE IsDelayN
和IsDelayS
的一部分。我不确定我将如何更改该代码。
最后,我得到的错误消息是TypeError: Cannot read property 'filter' of undefined
。我假设entity
未定义,因为feed
由于上述问题而成为空变量。有人能证实吗?如果是这样,有人能帮我解决吗?
const GetFeedData = (function () {
let feed, feedId;
return {
getFeedId: function () {
// All this does is take input from one of my React components
// and return the feed_id for the end of the url in the API call
},
getFeedData:
// This is the API call itself. It modifies the feed variable above but
// is asynchronous. The feed getter below is what's returning an unmodified
// variable,
get feed() { return feed; }
};
})();
const ReverseStop = (function () {
// This does some other stuff that I don't think factors into my question.
})();
export const IsDelayN = (function () {
let noDelay, yesDelay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
GetFeedData.getFeedData();
ReverseStop.reverseStop(sub, stop);
var arrivals = [];
var delays = [];
// The below IIFE is what's calling the 'entity' property that is supposed
// to be part of feed and which the TypeError is saying is undefined.
(function dataFilter () {
var feedObjs = GetFeedData.feed().entity.filter(function (entityObj) {
if (entityObj.trip_update !== null && entityObj.trip_update.stop_time_update.stop_id == ReverseStop.stopIdN) {
return entityObj.trip_update.stop_time_update;
}
});
// Now a whole bunch more mutations happen to the array I should have in feedObjs.
};
})();
export const IsDelayS = (function () {
// This is for all intents and purpses identical to IsDelayN
})();
答案 0 :(得分:1)
网上有很多关于回调和承诺的资料。我认为在继续阅读更多内容之前,你会获得最大的里程数,因为它是Web开发的必要组成部分(处理异步内容)。跳过你最后的评论:
var feedObjs = GetFeedData.getFeedData().entity.filter(etc)
getFeedData()
应该返回一个承诺。
getFeedData: function () {
return rp({ // <--- make sure your function returns
method: 'GET',
url: 'https://cors-anywhere.herokuapp.com/http://datamine.mta.info/mta_esi.php?key=MY_KEY&feed_id=' + feedId,
encoding: null
}).then((buf) => {
return GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(buf);
});
}
任何返回承诺的内容都可以通过链接.then
:
export const IsDelayN = (function () {
let noDelay, yesDelay;
return {
isDelay: function (sub, stop) {
GetFeedData.getFeedId(sub);
// ...
GetFeedData.getFeedData().then(function (entity) {
// code that needs to happen after async call goes here:
(function dataFilter () {
entity.filter(function (entityObj) {
if (entityObj.trip_update !== null && entityObj.trip_update.stop_time_update.stop_id == ReverseStop.stopIdN) {
return entityObj.trip_update.stop_time_update;
}
});
})()
})
}
}
})();
基本上,一旦你需要的是异步,任何在它之后编写的代码必须写在异步调用返回之后的范围内(如回调或.then
函数),而不是在&#34;下一行&#34;它将在异步调用返回之前执行。
这是一篇关于承诺的好文章:https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html