2016-12-25 4 views
8

Ich versuche, die Funktion zu schreiben, die alle Ergebnisse asynchroner Funktionen zurückgibt und einen Rückruf ausführt, der in ein Array einschiebt und das Ergebnis jeder asynchronen Funktion protokolliert.JS: Innere Funktionsargumente in asynchronen Funktionen erhalten und Rückruf ausführen

Als Kellner, der alle Gerichte bringt, wenn sie alle fertig sind. Ich verstehe nicht, wie die untergeordneten Argumente erhalten werden, die als Ergebnis zurückgegeben werden sollen. Der Code der Aufgabe und meine nicht funktionierende Lösung ist unten:

Die Aufgabe:

var dishOne = function(child) { 
    setTimeout(function() { 
     child('soup'); 
    }, 1000); 
}; 

var dishTwo = function(child) { 
    setTimeout(function() { 
     child('dessert'); 
    }, 1500); 
}; 
waiter([dishOne, dishTwo], function(results) { 
    console.log(results); // console output = ['soup', 'dessert'] 
}); 

Meine nicht funktionierende Lösung:

function child(arg) { 
    this.arr.push(arg) 
} 

function waiter(funcArray, doneAll) { 
    var result = { 
     arr: [] 
    }; 
    let i = 0; 
    const x = child.bind(result) 
    funcArray.forEach(function(f) { 
     f(x) 
     i++; 
     if(i == 2) { 
     doneAll(result.arr) 
     } 
    }); 
} 

Antwort

5

Problem ist dieser Teil:

funcArray.forEach(function(f) { 
    f(x) 
    i++; 
    if(i == 2) { 
    doneAll(result.arr) 
    } 
}); 

das ist eine synchrone Funktion, also wenn Sie if(i == 2) überprüfen, überprüfen Sie im Grunde, dass Sie alle a aufgerufen haben Synchronisierungsfunktionen, aber sie haben noch nichts zurückgegeben. Sie wissen also nur, dass die Funktionen aufgerufen wurden, aber result.arr noch nicht ausgefüllt ist.

Sie müssen den Ausdruck doneAll(result.arr) in child Callback verschieben, dann wird es von Async-Funktion aufgerufen, wie es Ergebnis zurückgibt.

Simpliest Lösung, die ich denken kann, ist Ihre child als

function child(arg) { 
    if (this.arr.push(arg) === this.allCount) this.doneAll(this.arr); 
} 

und in Ihrer waiter Funktion verbessern Ergebnisobjekt

var result = { 
    arr: [] 
    , allCount: funcArray.length 
    , doneAll: doneAll 
}; 

Schreiben Dies gilt arbeiten, hat aber einen Nachteil - Position der Ergebnisse nicht die Position der Funktionen in funcArray, die Position der Ergebnisse ist nach Dauer der asynchronen Funktion sortiert, einfach die erste aufgelöst würde das erste Ergebnis usw. nehmen. Wenn dies ein Problem ist, müssen Sie auch Index übergeben zu Ihrer child Funktion, um das Ergebnis an einer wertvollen Position im Ergebnisarray zu speichern, und dann würde die Überprüfung durch arr.length nicht funktionieren, weil JS Array die Länge als höchsten Index + 1 zurückgibt, also wenn Ihr letzter funcArray zuerst erfüllt würde, würde es den letzten Index füllen und die Länge von result.arr wird gleich this.allCount sein, also um die Reihenfolge des Ergebnisses wie funcArray zu halten, müssen Sie die Anzahl der zurückgegebenen Ergebnisse als eine andere Zahl speichern, diese Zahl mit jedem neuen Ergebnis erhöhen und diese Zahl mit allCount vergleichen.

Oder abschicken verringern wie so

function child(idx, arg) { 
    this.arr[idx] = arg; 
    if (--this.allCount === 0) this.doneAll(this.arr); 
} 

und ändern Sie Ihre waiter Funktion

function waiter(funcArray, doneAll) { 
    const result = { 
     arr: [] 
     , allCount: funcArray.length 
     , doneAll: doneAll 
    }; 

    funcArray.forEach(function(f, i) { 
     f(child.bind(result, i)); 
    }); 
} 
0

Warum nicht Promise?

function dishOne() { 
    return new Promise(function(resolve, reject) { 
     setTimeout(function() { resolve('soup') }, 1000) 
    }) 
} 

function dishTwo() { 
    return new Promise(function(resolve, reject) { 
     setTimeout(function() { resolve('dessert') }, 1500) 
    }) 
} 

Ihre waiter Funktion:

function waiter(dishes, callback) { 
    return Promise.all(dishes).then(callback) 
} 

Und Sie können es wie so viel

waiter([dishOne(), dishTwo()], function(results) { 
    // Invoked when all dishes are done 
    console.log(results) // ['soup', dessert'] 
}) 

verwenden leichter zu verstehen. Recht?

+0

oops, sorry, ich missverstand nur die Frage – Octopitus

Verwandte Themen