2017-09-27 59 views
0

我有一個未定義的數組,它在得到填充的for循環後得到解決的問題。它看起來像如下:在for循環中解析數組undefined後未定義數組

function mainFunction() { 
    getUnreadMails().then(function(mailArray) { 
     // Do stuff with the mailArray 
     // Here it is undefined 
    }) 
} 

function getUnreadMails() { 
    var mailArray = []; 
    return new Promise(function(resolve, reject) { 

     listMessages(oauth2Client).then(
      (messageIDs) => { 

       for(var i = 0; i < messageIDs.length; i++) { 
        getMessage(oauth2Client, 'me', messageIDs[i]).then(function(r) { 
         // Array gets filled 
         mailArray.push(r); 
        }, function(error) { 
         reject(error); 
        }) 
       } 
       // Array gets resolved 
       resolve(mailArray); 
      }, 
      (error) => { 
       reject(error); 
      } 
     ) 
    }); 
} 

兩個listMessages()getMessage()返回一個承諾,所以在這裏鏈。任何想法,爲什麼我得到一個undefined mailArray?我的猜測是,它在解決問題時還沒有填充。其次,我認爲這個流程不是一個好的做法。

+1

'getMessage'看起來像是異步的。這是行不通的,因爲你在調用getMessage之前調用resolve函數 –

+0

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all – epascarello

+0

@JoshuaK正是我的想法。這怎麼做到正確? – ffritz

回答

3

的陣列可能是undefined因爲它從未被定義;至少在你的代碼中沒有。你的承諾在你的循環中的任何迭代可以解決或更好地說,拋出(試圖push未定義)之前解決。

除此之外。您可以使用Array#mapPromise.all高度簡化代碼。

並且捕獲一個錯誤沒有意義,只是爲了重新拋出相同的錯誤而不做任何其他的操作。

function getUnreadMails() { 
    //put this on a seperate line for readability 
    //converts a single messageId into a Promise of the result 
    const id2message = id => getMessage(oauth2Client, 'me', id); 

    return listMessages(oauth2Client) 
     //converts the resolved messageId into an Array of Promises 
     .then(messageIDs => messageIDs.map(id2message)) 
     //converts the Array of Promises into an Promise of an Array 
     //.then(Promise.all.bind(Promise)); 
     .then(promises => Promise.all(promises)); 
    //returns a Promise that resolves to that Array of values 
} 

或短:

function getUnreadMails() { 
    return listMessages(oauth2Client) 
     .then(messageIDs => Promise.all(messageIDs.map(id => getMessage(oauth2Client, 'me', id)))) 
} 

。然後(Promise.all)將行不通

我想使中間結果更加清晰由它們分隔條件爲不同步驟/功能。但是我輸入得太快而沒有檢查。修復了代碼。

在短版,在那裏做了mailArray後來竟得到填補/解決

Promise.all()需要一個承諾的數組,並返回解析值的一個承諾(或第一拒絕) 。

messageIDs.map(...)返回一個數組及其周圍的Promise.all()將其轉換爲解析值的單個Promise。 而且由於我們在Promise鏈中返回了這個Promise,返回的承諾listMessages(oauth2Client).then(...)也解析爲這個值的數組。

+0

'。然後(Promise.all);' - 酷! – kharandziuk

+0

我真的很喜歡這種方法,謝謝!在短版本中,那麼mailArray實際上會被填充/解析? – ffritz

+1

'.then(Promise.all)'不起作用,它需要綁定到'Promise'。更好地將其移動到箭頭函數中。 – Bergi

0
  getMessage(oauth2Client, 'me', messageIDs[i]).then(function(r) { 
        // Array gets filled 
        mailArray.push(r); 
       }, function(error) { 
        reject(error); 
       }) 

是一個異步調用

resolve(mailArray); 

不會等待它推送數據,並會解決的手前陣

到甲階酚醛這個你應該使用Promise.all()

function mainFunction() { 
    getUnreadMails().then(function(mailArray) { 
     // Do stuff with the mailArray 
     // Here it is undefined 
    }) 
} 

function getUnreadMails() { 
    var mailArray = []; 

    return listMessages(oauth2Client).then(
     (messageIDs) => { 

      for(var i = 0; i < messageIDs.length; i++) { 
       mailArray.push(getMessage(oauth2Client, 'me', messageIDs[i])); 
      } 
      // Array gets resolved 
      return Promise.all(mailArray); 
     }, 
     (error) => { 
      reject(error); 
     } 
     ) 
} 
+0

好的,getMessage完成後如何解決? – ffritz

+0

編輯了答案,請查看 – marvel308

0

剛剛接過marvel308的答案,我認爲你需要創建一個新的Promise可以解決你的其他問題。我還沒有機會測試這一點,但我認爲這應該工作

function getUnreadMails() { 

    var mailArray = []; 

    return new Promise(function(resolve, reject) { 

     listMessages(oauth2Client).then(
      (messageIDs) => { 

       var messages = []; 

       for(var i = 0; i < messageIDs.length; i++) { 
        messages.push(
         getMessage(oauth2Client, 'me', messageIDs[i]).catch(reject) 
        ); 
       } 

       Promise.all(messages).then(resolve); 

      }, 
      (error) => { 
       reject(error); 
      } 
     ) 
    }); 

} 

這樣,你的第一個應許的resolve被調用時,所有的messages已經解決

+1

您仍然需要避免['Promise' constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern - 和 - 如何對避免-吧)! – Bergi

+0

好喊。我正在尋找一個快速解決方案,但你是對的 - 我們應該避免反模式 –

0

Explicit construction is an anti-pattern

我相信你可以寫一段代碼更短,恕我直言,清潔

function mainFunction() { 
    getUnreadMails().then(function(mailArray) { 
    // Do stuff with the mailArray 
    // Here it is undefined 
    }) 
} 

function getUnreadMails() { 
    return listMessages(oauth2Client) 
     .then((messageIDs) => Promise.all(messageIDs.map(id => getMessage(oauth2Client, 'me', id))) 

} 
+1

'.then(Promise.all)'不起作用,它需要綁定到'Promise'。更好地將其移動到箭頭函數中。 – Bergi

0

由於您getMessage功能是異步,以及你需要等到所有呼叫完成。

我會建議使用Promise.all

在這裏你可以找到更多的信息:MDN Promise.all()

的代碼會是這個樣子:

messageIDs.map(...)返回Promises

使用Promise.all()數組獲得所有承諾響應的陣列

resolve如果值是正確的,否則reject

function mainFunction() { 
     getUnreadMails().then(function(mailArray) { 
     // Do stuff with the mailArray 
     // Here it is undefined 
     }) 
    } 

    function getUnreadMails() { 
    return new Promise(function(resolve, reject) { 
     listMessages(oauth2Client).then(
      (messageIDs) => { 
       return Promise.all(messageIDs.map(id => getMessage(oauth2Client, 'me', id))) 
     }) 
     .then((messages) => resolve(messages)) 
     .catch(error => reject(error)) 
    }); 
} 

有一點要記住的是,Promise.all()拒絕您的任何承諾未能

希望這有助於!

+0

我明白了,現在有道理,謝謝!托馬斯答案中的解析部分在我認爲的下面的短小部分中不存在。 – ffritz

+0

其實我覺得他的回答很好,我很漂亮,應該也能工作 –

+0

我認爲人們認爲我的getMessage()返回一個消息數組,但實際上它返回一個消息,它需要存儲在mailArray ,然後在每個消息被檢索後,需要解析mailArray。 – ffritz