如何使用async等待回调函数从异步函数返回值?

问题描述:

我是新来的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

我感兴趣的是使用的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中。 –

await只能用在一个异步函数里,它用来等待一个Promise被解决,而不是你想要的。

要清理代码,请稍微看一下Promises,但不要指望它会让你的代码看起来不那么难看,你只需将一个“回调”地狱变成一个“然后”地狱。

+0

整个块包含在异步函数中,我将发布明天的完整代码 – Danish