2017-05-28 70 views
0

我正在加載存儲在幾個JSON中的論壇數據,以便在網站上顯示,然後使用React進行渲染。數據本身分爲兩種類型的文件:線程數據和用戶數據。Promise.all解決得太早

// threads/135.json 
{ 
    "title": "Thread Title", 
    "tid": 135, 
    "posts": [ 
    { 
     "pid": 1234, 
     "timestamp": 1034546400, 
     "body": "First forum post", 
     "user": 5678 
    }, 
    { 
     "pid": 1235, 
     "timestamp": 103454700, 
     "body": "Reply to first forum post", 
     "user": 9876 
    } 
    ] 
} 

一旦線程數據被加載時,用戶數據基於用戶ID被加載。

// user/1234.json 
{ 
    "id": 1234, 
    "name": "John Doe", 
    "location": "USA" 
} 

實際的代碼是基於Google's Introduction to Promises,變成了一個功能,它看起來是這樣的:

export default function loadData(id) { 

    var didLoadUser = []; 
    var dataUsers = {}; 
    var dataThread = {}; 

    getJSON('./threads/' + id + '.json').then(function(thread) { 
    dataThread = thread; 

    // Take an array of promises and wait on them all 
    return Promise.all(
     // Map our array of chapter urls to 
     // an array of chapter json promises 
     thread.posts.map(function(post) { 
     if (post.user > 0 && didLoadUser.indexOf(post.user) === -1) { 
      didLoadUser.push(post.user); 
      return getJSON('./users/' + post.user + '.json') ; 
     } 
     }) 
    ); 
    }).then(function(users) { 
    users.forEach(function(user) { 
     if (typeof user !== 'undefined') { 
     dataUsers[user.id] = user; 
     } 
    }); 
    }).catch(function(err) { 
    // catch any error that happened so far 
    console.error(err.message); 
    }).then(function() { 
    // use the data 
    }); 
} 

// unchanged from the mentioned Google article 
function getJSON(url) { 
    return get(url).then(JSON.parse); 
} 

// unchanged from the mentioned Google article 
function get(url) { 
    // Return a new promise. 
    return new Promise(function(resolve, reject) { 
    // Do the usual XHR stuff 
    var req = new XMLHttpRequest(); 
    req.open('GET', url); 

    req.onload = function() { 
     // This is called even on 404 etc 
     // so check the status 
     if (req.status == 200) { 
     // Resolve the promise with the response text 
     resolve(req.response); 
     } 
     else { 
     // Otherwise reject with the status text 
     // which will hopefully be a meaningful error 
     reject(Error(req.statusText)); 
     } 
    }; 

    // Handle network errors 
    req.onerror = function() { 
     reject(Error("Network Error")); 
    }; 

    // Make the request 
    req.send(); 
    }); 
} 

本身其轉換成被稱爲我的部件的componentWillMount功能函數之前工作的罰款的代碼。

componentWillMount: function() { 
    this.setState({ 
     data: loadData(this.props.params.thread) 
    }) 
} 

我懷疑錯誤在於功能本身,因爲它看起來像Promise.all被加載線程數據後加載任何用戶數據之前解決。

我最近纔開始使用承諾,所以我的知識很基礎。我究竟做錯了什麼?我是否需要將主函數封裝在另一個承諾中?

+0

你如何調用函數/你期望的結果? –

+0

你的承諾鏈看起來很好,我認爲問題在於他的答案中提到的@loan可視化(反應)。 – Hosar

+0

'loadData()'需要返回一個promise,而'loadData()'的調用者需要使用promise來訪問結果。 – jfriend00

回答

2
this.setState({ 
    data: loadData(this.props.params.thread) 
}) 

不能從異步調用返回像上面的數據只是不在同步方式準備時間。您返回承諾,因此代碼應該看起來像如:

loadData(this.props.params.thread) 
.then((data)=> { 
    this.setState({ 
    data, 
    }) 
}) 

注: 爲了得到它的工作,你需要回報loadData的承諾,因此:

... 
return getJSON(.. 
...