2017-07-27 81 views
5

Jestem nowy nodejs i jest zwrotna cholery, czytałem o asynchroniczny/Oczekujcie wprowadzenie w węźle 8 i był zainteresowany, aby wdrożyć go w ten sposóbJak zwracać wartości z asynchronicznych funkcji za pomocą async, oczekując od funkcji wywołania zwrotnego?

mam konkretny zestaw metod, które trzeba zadzwonić w synchronicznym sposób, jeden po drugim na Trello API np

  1. stworzenia pokładzie
  2. tworzenia etykiet przy użyciu karty id
  3. tworzenia kart przy użyciu karty id
  4. oklejaj karty
  5. tworzyć listy w karcie
  6. dodać każdą pozycję do listy na karcie

można sobie wyobrazić w nodejs wymaga to znacznych callbacków zagnieżdżone w siebie, by przejść do poprzedniego obiektu

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); 
              }); 
             }); 
            }); 
           }); 
          }); 
         }); 
        }); 
       }); 
      }); 
     }); 
    } 

Nadal mam problemy z powyższym kodem, gdzie __. Każda pętla jest zaangażowana, wywołuje asynchronicznie wszystkie funkcje w pętli (zmieniając kolejność elementów, w których powinny być pierwotnie) - więc pomyślałem, że musi być lepszym sposobem synchronizowania połączeń

Jestem zainteresowany wykorzystaniem czekają/asynchronicznie oczyścić kod, ale działa w kłopoty po powrocie do obiektu z zwrotnego async

Rozwiązanie oparte jest na sails.js, co następuje fragment z TrelloService Piszę

rozważyć następujące kwestie:

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); 
     } 
} 

muszę wartość płyty mają być dostępne w wezwaniu żądanie etykiety, jakim jestem w stanie pobrać obiekt płyty, choć wydarzenie Przygotowałem się na słowa kluczowe

muszę być w stanie uzyskać obiektów z oddzwonić funkcje i wykorzystać je do późniejszego wywołania funkcji w sposób synchroniczny

Używam Trello api otoki Node-Trello dokonać połączeń (T)

Jednym ze sposobów jest zawarcie powyższego opisu w większej liczbie funkcji za pomocą wywołania zwrotnego w następujący sposób, ale nie sądzę, że byłaby to najlepsza praktyka, ponieważ musiałbym pisać zwrotne wywołania zwrotne na każdym obiekcie, który powinienem użyć

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 
}); 

wszelkie sugestie są doceniane

+0

Próbuję przeczytać kod, ale nic nie ma większego sensu ... Jeśli to tylko ja, a twój kod pracował w callbacku, trzymaj się tego. Aby zmniejszyć piekło wywołania zwrotnego, możesz po prostu zmienić na mniejsze funkcje i użyć ich jako wywołań zwrotnych ... – Salketer

+0

Będę wysyłać pełny kod później, więc ma to więcej sensu – Danish

Odpowiedz

5

Jestem zainteresowany wykorzystaniem czekają/asynchronicznie oczyścić kod

Istnieją dwa kroki do tego: promisification i asynchroniczny. Twój kod jest coraz bardziej zagubiony, ponieważ pomija pierwszy krok.

Promisyfikacja tworzy bardzo proste funkcje zwrotne obiecujące wokół funkcji wywołania zwrotnego. Na przykład, jeśli t jest instancją klasy Trello:

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

sekund krokiem jest napisanie logiki async/await korzystając obietnica powrotu funkcji i nie wywołania zwrotne. Ponieważ są obiecujące, kodowanie jest znacznie bardziej naturalne:

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; 
} 

Krok promizacyjny jest żmudny i powtarzalny. Istnieje kilka bibliotek, które mogą zautomatyzować zwroty od wezwania do obietnicy, w szczególności Bluebird.

+0

Myślę, że to może być droga - pochodząca z tła aC#, moje zrozumienie jest trochę inne na oczekiwanie/asynchroniczne - odniosłem wrażenie, że nie będzie potrzeby obietnic po oczekiwaniu/asynchronizacji – Danish

+1

'Obietnica' jest analogiczna do' Zadanie ', a promisyfikacja jest analogiczna do [Owijarki TAP dla APM] (https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/interop- z-innymi-asynchronicznymi-wzorami-i-typami # ApmToTap) - zawijanie asynchronicznego kodu w starym stylu do nowych stylów API zgodnych z asynchronizacją. –

1

await może być używany tylko wewnątrz funkcji asynchronicznej, zwykle czekał na rozwiązanie Obietnicy, a nie na to, co chcesz.

Aby oczyścić swój kod, spójrz na Obietnice, ale nie spodziewaj się, że sprawi to, że twój kod będzie mniej brzydki, po prostu zmienisz piekło "oddzwonienia" w piekło "wtedy".

+0

Cały blok jest zawarty w funkcji asynchronicznej, będę publikować pełny kod jutro – Danish