2017-07-27 508 views
5

我是新來的NodeJS和它的回調地獄,我讀到異步/ AWAIT引入節點8和有興趣來實現它的方式如何使用async等待回調函數從異步函數返回值?

我有一組特定的方法,我需要在一個同步調用方式陸續爲trello API 如

  1. 創建板
  2. 創建標籤使用板卡ID
  3. 創建卡使用板卡ID
  4. 貼上標籤卡
  5. 創建列表中添加的每個項目在卡片列出

你可以的NodeJS想象,這需要嵌套到彼此顯著回調訪問以前的對象

createProjectBoard: function (project) { 
     t.post("1/board", { 
      name: project.name, 
      desc: project.description, 
      defaultLists: false 
     }, function (err, board) { 
      if (err) { 
       console.log(err); 
       throw err; 
      } 

      //get board id from data 
      let boardId = board.id 
      let backlogListId = ""; 
      let highId = "", mediumId = "", lowId = ""; 

      //create labels 
      t.post("1/labels", { 
       name: 'High', 
       color: 'red', 
       idBoard: boardId 
      }, function (err, label) { 
       console.log(err || 'High label created'); 
       if (err) return; 
       highId = label.id; 
      }); 

      t.post("1/labels", { 
       name: 'Medium', 
       color: 'orange', 
       idBoard: boardId 
      }, function (err, label) { 
       console.log(err || 'Medium label created'); 
       if (err) return; 
       mediumId = label.id; 
      }); 

      t.post("1/labels", { 
       name: 'Low', 
       color: 'yellow', 
       idBoard: boardId 
      }, function (err, label) { 
       console.log(err || 'Low label created'); 
       if (err) return; 
       lowId = label.id; 
      }); 

      //create rest of the lists 
      t.post("1/lists", { name: "Completed", idBoard: boardId }, function (e, l) { 
       if (e) { 
        console.log(e); 
        return; 
       } 
       console.log(l); 
       t.post("1/lists", { name: "Testing", idBoard: boardId }, function (e, l) { 
        if (e) { 
         console.log(e); 
         return; 
        } 
        console.log(l); 
        t.post("1/lists", { name: "In Progress", idBoard: boardId }, function (e, l) { 
         if (e) { 
          console.log(e); 
          return; 
         } 
         console.log(l); 

         //create backlog list 
         t.post("1/lists", { name: "Backlog", idBoard: boardId }, function (e, list) { 
          if (e) { 
           console.log(e); 
           return; 
          } 
          console.log(list); 
          backlogListId = list.id; 
          console.log("backlog card list id:" + backlogListId); 

          _.each(project.userStories, function (story) { 
           //assign labels 
           let labelId = ""; 
           switch (story.complexity.toLowerCase()) { 
            case 'high': 
             labelId = highId; 
             break; 
            case 'medium': 
             labelId = mediumId; 
             break; 
            default: 
             labelId = lowId; 
           } 

           t.post("1/cards", { 
            name: story.title, 
            idLabels: labelId, 
            idList: backlogListId 
           }, function (e, card) { 
            if (e) { 
             console.log(e); 
             return; 
            } 
            let cardId = card.id; 
            console.log("created id:" + cardId + ";card:" + story.title);          

            t.post("1/cards/" + cardId + "/checklists", { 
             name: "Acceptance Criteria" 
            }, function (e, checklist) { 
             if (e) { 
              console.log(e); 
              return; 
             } 
             console.log('checklist created:'); 
             var clId = checklist.id; 
             _.each(story.criterion, function (criteria) { 
              t.post("1/cards/" + cardId + "/checklist/" + clId + "/checkItem", { 
               name: criteria 
              }, function (e, checkItem) { 
               if (e) { 
                console.log(e); 
                return; 
               } 
               console.log('created check item:' + checkItem); 
              }); 
             }); 
            }); 
           }); 
          }); 
         }); 
        }); 
       }); 
      }); 
     }); 
    } 

我仍然遇到上述代碼的問題,其中__。涉及每個循環,它異步地調用循環中的所有函數(重新排列它們本來應該是的項目順序) - 所以我認爲那裏必須是更好的方式來同步進行呼叫

我感興趣的是使用的await /異步清理的代碼,而是從異步回調

的解決方案是基於在sails.js返回對象中運行了一些麻煩,下面是摘錄從TrelloService我寫

考慮以下幾點:

createProjectBoard: async function(project) { 
     //get board id from data 
     let board; 
     let boardId = ""; 
     let backlogListId = ""; 
     let highId = "", 
      mediumId = "", 
      lowId = ""; 


     try { 
      await t.post("1/board", { 
        name: project.name, 
        desc: project.description, 
        defaultLists: false 
       }, 
       function(err, b) { 
        if (err) { 
         console.log(err); 
         throw err; 
        } 
        console.log("board" + b); 
        board = b; 
       }); 

      //create labels 
      await t.post("1/labels", { 
       name: 'High', 
       color: 'red', 
       idBoard: board.id 
      }, function(err, label) { 
       console.log(err || 'High label created'); 
       if (err) return; 
       highId = label.id; 
      }); 

     } catch (err) { 
      console.log(err); 
     } 
} 

我需要董事會值是在標籤請求調用可用的,到目前爲止,我無法檢索板實物,事件雖然我已經安裝了關鍵字

我需要能夠得到來自回調函數的對象,並用它們爲後續的函數調用以同步的方式

我使用的是trello API包裝節點trello打的電話(T)

一種方法是將上面的回調包裝在更多的函數中,如下所示,但我不認爲這是最佳實踐,因爲我必須在每個需要使用的對象上編寫包裝回調函數

function foo(url,options,cb){ 
await t.post(url, options, 
     function(err, b) { 
      if (err) { 
       console.log(err); 
       throw err; 
      } 
      console.log("board" + b); 
      cb(b); 
     }); 
} 

var url = "1/board"; 
var options = { 
      name: project.name, 
      desc: project.description, 
      defaultLists: false 
     }; 

foo(url,options,function(board){ 
    console.log(board); //board object 
}); 

任何建議,將不勝感激

+0

我正在嘗試閱讀代碼,但沒有什麼意義......如果它只是我,並且您的代碼在回調中工作,只需堅持這一點。爲了減少回調地獄,你可以簡單地重構爲更小的函數,並將它們用作回調函數... – Salketer

+0

稍後我會發布完整的代碼,因此它更有意義 – Danish

回答

5

我感興趣的是使用的await /異步清理代碼

有兩個步驟,以這樣的:promisification和異步。你的代碼越來越困惑,因爲它跳過了第一步。

Promisification在回調函數週圍創建了非常簡單的承諾返回包裝函數。例如,如果tTrello類的實例:

Trello.prototype.postAsync = (url, data) => new Promise((resolve, reject) => { 
    this.post(url, data, (err, result) => { 
    if (err) { reject(err); } 
    else { resolve(result); } 
    }); 
}); 

步驟是寫async/await邏輯,使用許返回功能和不回調。由於他們是承諾返回,他們的代碼更自然:

const board = await t.postAsync("1/board", { 
    name: project.name, 
    desc: project.description, 
    defaultLists: false 
}); 
console.log("board" + board); 

//create labels 
let highId; 
try { 
    highId = await t.postAsync("1/labels", { 
     name: 'High', 
     color: 'red', 
     idBoard: board.id 
    }); 
} catch (err) { 
    console.log(err || 'High label created'); 
    return; 
} 

promisification步驟是單調乏味和重複。有一些庫可以自動執行回調 - 承諾,最顯着的是Bluebird

+0

我認爲這可能是要走的路 - 從ac#背景來看,我的理解對於await/async有點不同 - 我的印象是,在等待/異步實現之後不需要promise – Danish

+1

'Promise'類似於'Task ',promisification類似於[APAP的TAP包裝器](https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/interop- with-other-asynchronous-patterns-and-types#ApmToTap) - 將舊式異步代碼封裝到新式異步兼容API中。 –

1

await只能用在一個異步函數裏,它用來等待一個Promise被解決,而不是你想要的。

要清理代碼,請稍微看一下Promises,但不要指望它會讓你的代碼看起來不那麼難看,你只需將一個「回調」地獄變成一個「然後」地獄。

+0

整個塊包含在異步函數中,我將發佈明天的完整代碼 – Danish