2017-08-31 2 views
1

In meiner React-Anwendung habe ich ein Array von Parametern (z. B. einige IDs), die als Parameter für eine Ajax-Anrufwarteschlange verwendet werden sollten. Das Problem ist, dass das Array mehr als 1000 Elemente enthalten könnte und wenn ich den Ajax-Aufruf nur rekursiv über die forEach-Schleife mache, reagiert die Browser-Seite möglicherweise nicht mehr, bevor alle Anforderungen gelöst sind.JavaScript, React - Senden mehrerer simultaner Ajax-Aufrufe

Gibt es eine Technik/Bibliothek, die es erlauben würde, Ajax-Anfragen z. B. gleichzeitig mit 5 Anfragen asynchron zu senden, und erst dann, wenn diese fertig sind, die nächsten 5?

Follow-up-Fragen:

React - Controlling multiple Ajax Calls

React - Controlling AJAX calls made to the server

Antwort

2

, wenn Sie nicht es Version eingeschränkt sind und es6 verwenden können, dann sollten Sie in async aussehen await

async function makeBatchCalls(arrayIds, length) { 
 
let test = arrayIds.reduce((rows, key, index) => (index % length == 0 ? rows.push([key]) 
 
       : rows[rows.length-1].push(key)) && rows, []); 
 
let Batchresults = []; 
 
       //convert them to two dimensionl arrays of given length [[1,2,3,4,5], [6,7,8,9,10]] 
 
for (calls of test) { 
 
    Batchresults.push(await Promise.all(calls.map((call)=>fetch(`https://jsonplaceholder.typicode.com/posts/${call}`)))); 
 
} 
 
return Promise.all(Batchresults); //wait for all batch calls to finish 
 
} 
 
makeBatchCalls([1,2,3,4,5,6,7,8,9,10,12,12,13,14,15,16,17,18,19,20],3)

async/await gemeint für das genaue Szenario des Wartens auf Async-Aufrufe. Im Wesentlichen innerhalb der Async-Funktion, bis das Warten beendet ist, wird die Ausführung angehalten. Sie müssen Versprechungen und Generatoren verstehen, bevor Sie sie verwenden.

+0

Leider hat dies nicht funktioniert, warten nicht warten auf die 5 Anrufe zu vervollständigen, bevor eine andere feuern einstellen. –

+0

HI könnten Sie versuchen, dieses Snippet? Ich fühle mich für eine schlechte Gotcha im Grunde erwarten Arbeiten nur innerhalb der Hauptfunktion es wird nicht erwarten innere Funktion (Kartenfunktion im alten Code). Dies sollte funktionieren –

+0

Jetzt möchte ich einen Server-Aufruf nach Abschluss jedes dieser Versprechen machen. –

2

Ok, lassen Sie uns einige Dinge aussortieren. In JavaScript AJAX-Anfragen sind von Natur aus asynchron. Sie haben sich dafür entschieden, sie in Ihrer Implementierung etwas synchron zu machen.

Was Sie tun müssen, ist ein Array von Anfragen, von denen Sie Ergebnisse X auf einmal knallen, warten auf sie zurückzukehren, und zu wiederholen.

let ids = [a lot of ids here] 

while (ids.length > 0) { 

    let c = ids.splice(0, 5) 
    let promises = [] 
    for (let i = 0; i < c.length; i++) { 
     promises.push(fetch("someURL").then(function() {})) 
    } 
    Promise.all(promises) 
} 

5 Anfragen ausführen gleichzeitig, warten, bis sie vervollständigen dann nächsten Teil der IDs

+0

Danke für den Kommentar, ich habe speziell überprüft, ob es eine Bibliothek gibt, die mir dabei hilft. Oder vielleicht eine Bibliothek wie Superagent oder Axios kann sich darum kümmern? –

+0

@LokeshAgrawal dann heißt es Bibliothek, nicht "Technik" –

+0

Das ist sehr sauber und elegant, vielen Dank :) –

1

In dieser Art von Fällen holen, ist es am besten in Backend zu ändern, in dem Sie die Ergebnisse für tausend Eingaben verarbeiten können schicke sie statt tausendmal anzurufen. Ein anderer Weg ist, promise zu verwenden, denke ich.

Sie können auch auf this link schauen, wenn es für Sie anwendbar ist. Ich denke, diese Dinge beantworten Ihre Frage

2

Ich hatte das gleiche Problem in einem Projekt. Was Sie brauchen, ist eine Prioritätswarteschlange, um zu steuern, wie viele Anfragen gleichzeitig ausgeführt werden. Ich verwende this library. Da die Implementierung der p-Queue einfach zu verstehen ist und nicht so groß ist, habe ich den Code in das Snippet eingefügt, um Ihnen zu zeigen, wie es in den letzten Zeilen funktioniert.

// IMPLEMENTATION #################### 
 

 
// Port of lower_bound from http://en.cppreference.com/w/cpp/algorithm/lower_bound 
 
// Used to compute insertion index to keep queue sorted after insertion 
 
function lowerBound(array, value, comp) { 
 
    let first = 0; 
 
    let count = array.length; 
 

 
    while (count > 0) { 
 
    const step = (count/2) | 0; 
 
    let it = first + step; 
 

 
    if (comp(array[it], value) <= 0) { 
 
     first = ++it; 
 
     count -= step + 1; 
 
    } else { 
 
     count = step; 
 
    } 
 
    } 
 

 
    return first; 
 
} 
 

 
class PriorityQueue { 
 
    constructor() { 
 
    this._queue = []; 
 
    } 
 

 
    enqueue(run, opts) { 
 
    opts = Object.assign({ 
 
     priority: 0 
 
    }, opts); 
 

 
    const element = { 
 
     priority: opts.priority, 
 
     run 
 
    }; 
 

 
    if (this.size && this._queue[this.size - 1].priority >= opts.priority) { 
 
     this._queue.push(element); 
 
     return; 
 
    } 
 

 
    const index = lowerBound(this._queue, element, (a, b) => b.priority - a.priority); 
 
    this._queue.splice(index, 0, element); 
 
    } 
 

 
    dequeue() { 
 
    return this._queue.shift().run; 
 
    } 
 

 
    get size() { 
 
    return this._queue.length; 
 
    } 
 
} 
 

 
class PQueue { 
 
    constructor(opts) { 
 
    opts = Object.assign({ 
 
     concurrency: Infinity, 
 
     queueClass: PriorityQueue 
 
    }, opts); 
 

 
    if (opts.concurrency < 1) { 
 
     throw new TypeError('Expected `concurrency` to be a number from 1 and up'); 
 
    } 
 

 
    this.queue = new opts.queueClass(); // eslint-disable-line new-cap 
 
    this._queueClass = opts.queueClass; 
 
    this._pendingCount = 0; 
 
    this._concurrency = opts.concurrency; 
 
    this._resolveEmpty =() => {}; 
 
    this._resolveIdle =() => {}; 
 
    } 
 

 
    _next() { 
 
    this._pendingCount--; 
 

 
    if (this.queue.size > 0) { 
 
     this.queue.dequeue()(); 
 
    } else { 
 
     this._resolveEmpty(); 
 

 
     if (this._pendingCount === 0) { 
 
     this._resolveIdle(); 
 
     } 
 
    } 
 
    } 
 

 
    add(fn, opts) { 
 
    return new Promise((resolve, reject) => { 
 
     const run =() => { 
 
     this._pendingCount++; 
 

 
     fn().then(
 
      val => { 
 
      resolve(val); 
 
      this._next(); 
 
      }, 
 
      err => { 
 
      reject(err); 
 
      this._next(); 
 
      } 
 
     ); 
 
     }; 
 

 
     if (this._pendingCount < this._concurrency) { 
 
     run(); 
 
     } else { 
 
     this.queue.enqueue(run, opts); 
 
     } 
 
    }); 
 
    } 
 

 
    addAll(fns, opts) { 
 
    return Promise.all(fns.map(fn => this.add(fn, opts))); 
 
    } 
 

 
    clear() { 
 
    this.queue = new this._queueClass(); // eslint-disable-line new-cap 
 
    } 
 

 
    onEmpty() { 
 
    // Instantly resolve if the queue is empty 
 
    if (this.queue.size === 0) { 
 
     return Promise.resolve(); 
 
    } 
 

 
    return new Promise(resolve => { 
 
     const existingResolve = this._resolveEmpty; 
 
     this._resolveEmpty =() => { 
 
     existingResolve(); 
 
     resolve(); 
 
     }; 
 
    }); 
 
    } 
 

 
    onIdle() { 
 
    // Instantly resolve if none pending 
 
    if (this._pendingCount === 0) { 
 
     return Promise.resolve(); 
 
    } 
 

 
    return new Promise(resolve => { 
 
     const existingResolve = this._resolveIdle; 
 
     this._resolveIdle =() => { 
 
     existingResolve(); 
 
     resolve(); 
 
     }; 
 
    }); 
 
    } 
 

 
    get size() { 
 
    return this.queue.size; 
 
    } 
 

 
    get pending() { 
 
    return this._pendingCount; 
 
    } 
 
} 
 

 

 
// TEST #################### 
 

 

 
const promises = new PQueue({ 
 
    concurrency: 4 
 
}); 
 

 
const makePromise = (key, time) => { 
 
    let response = null; 
 
    return new Promise(resolve => { 
 
    setTimeout(() => { 
 
     response = `Promise ${key} resolved`; 
 
     console.log(response); 
 
     resolve(response); 
 
    }, time); 
 
    }); 
 
} 
 

 
promises.add(() => makePromise('p1', 5000)); 
 
promises.add(() => makePromise('p2', 1000)); 
 
promises.add(() => makePromise('p3', 3000)); 
 
promises.add(() => makePromise('p4', 6000)); 
 
promises.add(() => makePromise('p5', 2000)); 
 
promises.add(() => makePromise('p6', 1500)); 
 
promises.add(() => makePromise('p7', 5500)); 
 
promises.add(() => makePromise('p8', 7000)); 
 

 
promises.onIdle().then(() => { 
 
    console.log('Promises queue empty.'); 
 
});

+0

Danke Juliobetta, aber das scheint zu viel Code zu sein. Wie unterscheidet sich das vom Code von Shyam Babu? –

+0

Beide lösen Ihr Problem ... Die Lösung von shyam babu ist direkter, während die PQueue Ihnen weitere Möglichkeiten bietet, wie die Priorität einer Anfrage und Ereignisse wie 'onIdle' und' onEmpty' zu definieren. – juliobetta

+0

Please Opine auf https://stackoverflow.com/questions/46251862/react-controlling-multiple-ajax-calls, eine Follow-up-Frage –

Verwandte Themen