[英]How to delay execution of javascript function until JSON has loaded
I have a page that chains two API calls, loads the data into first_data
and second_data
before executing a createPage
function (which is several kb of data manipulation and d3.js): 我的页面链接了两个API调用,并在执行
createPage
函数之前将数据加载到first_data
和second_data
(这是几KB的数据操作和d3.js):
<script src="createPage.js"></script>
<script>
var first_data, second_data = [], [];
function getFirstData(){
return new Promise(function(resolve) {
var xhr = new XMLHttpRequest();
var url = "/API/my-request?format=json"
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
first_data = JSON.parse(xhr.responseText);
resolve('1');
}
}
xhr.open("GET", url, true);
xhr.send();
});
} //similar function for getSecondData()
getFirstData()
.then(getSecondData)
.then(createPage(first_data, second_data));
</script>
The trouble is that some of the code that manipulates the data in createPage
is showing errors, for example " can't convert undefined to object
". 问题在于,一些操作
createPage
数据的代码显示错误,例如“ can't convert undefined to object
”。 In that particular error's case, it's because I try to do Object.keys(data[0])
on some data that should be loaded from the API requests. 在这种特定错误的情况下,这是因为我尝试对应该从API请求加载的某些数据执行
Object.keys(data[0])
。 Some observations: 一些观察:
can't convert undefined
, then the page draws but all the graphics indicate that they were populated with no data. can't convert undefined
,那么该页面会绘制,但是所有图形均表明它们中没有数据。 console.log("starting")
statement at the start and end of createPage()
. createPage()
的开始和结尾处插入了console.log("starting")
语句。 Looking at the network and js console output when I load, the starting
output occurs before the two API GET requests are displayed in the network activity. starting
输出发生在网络活动中显示两个API GET请求之前。 Is this representative of what's really happening (ie can you mix javascript console and network console timing?) So, clearly I don't have access to the data at the point when I need it. 因此,很明显,在需要时我无法访问数据。
Promises
incorrect? Promises
不正确吗?
Promise.prototype.then()
expects 2 arguments(onFulfilled & onRejected
) asfunction-expression(OR handler or callback)
as it is a function(handler) which will be invoked when Promise is fulfilledPromise.prototype.then()
期望有2个参数(onFulfilled & onRejected
)作为function-expression(OR handler or callback)
因为它是一个函数(处理程序),当Promise实现时将被调用
In your case, createPage(first_data, second_data)
will invoke the function createPage
when statement is interpreted by interpreter. 在您的情况下,当解释器解释语句时,
createPage(first_data, second_data)
将调用函数createPage
。
Use anonymous function
as an argument and invoke your function inside it. 使用
anonymous function
作为参数并在其中调用您的函数。
getFirstData()
.then(getSecondData)
.then(function() {
createPage(first_data, second_data);
});
Edit: If you are not passing any arguments specifically to the callback, you can use .then(FUNCTION_NAME)
编辑:如果您没有将任何参数专门传递给回调,则可以使用
.then(FUNCTION_NAME)
In functional programming and using promises, you should probably refactor getFirstData (and getSecondData) to the following form: 在函数式编程和使用Promise时,您可能应该将getFirstData(和getSecondData)重构为以下形式:
function getFirstData(){
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
var url = "/API/my-request?format=json"
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
// Resolve the result, don't assign it elsewhere
resolve(JSON.parse(xhr.responseText));
} else {
// Add rejection state, don't keep the promise waiting
reject("XHR Error, status = ", xhr.status);
}
}
xhr.open("GET", url, true);
xhr.send();
});
}
And then resolve the promises like this (assume first & second data is not dependant on each other) 然后像这样解决承诺(假设第一和第二数据互不依赖)
Promise.all([getFirstData(), getSecondData()]).then(function(allData){
var first_data = allData[0];
var second_data= allData[1];
return createPage(first_data, second_data);
}).catch(function(error){
console.log("Error caught: ", error);
});
To make things even cleaner, you can change createPages's from: 为了使事情更加整洁,您可以从以下位置更改createPages:
function createPage(first_data, second_data){
// Function body
}
to 至
function createPage(data){
var first_data = data[0];
var second_data= data[1];
// Function body
}
and the Promise part: 和Promise部分:
Promise.all([getFirstData(), getSecondData()]).then(createPage);
Notice how short it became? 请注意它变短了吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.