EN
JavaScript - AJAX / fetch requests with multiplexing
6 points
In this short article we would like to show how to write in JavaScript own logic that joins in proper order as single array of results of many requests. Presented solution uses as configuration to know about items distibution in returned list. When it is necessary the logic maked AJAX request to complete needed data.
Example code:
xxxxxxxxxx
1
function RequestMultiplexer(proportions, request) {
2
var capacity = 0;
3
var states = [ ];
4
var processing = false;
5
var instances = { };
6
for (var i = 0; i < proportions.length; ++i) {
7
var proportion = proportions[i];
8
var type = proportion.type;
9
var count = proportion.count;
10
var instance = instances[type];
11
if (instance) {
12
instance.limit += count;
13
} else {
14
instances[type] = {
15
offset: 0,
16
limit: count,
17
storage: [ ]
18
};
19
}
20
capacity += count;
21
}
22
for (var i = 0; i < proportions.length; ++i) {
23
var proportion = proportions[i];
24
states.push({
25
type: proportion.type,
26
limit: proportion.count,
27
instance: instances[proportion.type]
28
});
29
}
30
function removeState(type) {
31
for (var i = states.length - 1; i > -1; --i) {
32
var state = states[i];
33
if (state.type == type) {
34
states.splice(i, 1);
35
}
36
}
37
}
38
this.request = function(callback) {
39
if (processing || states.length == 0) {
40
return false;
41
}
42
processing = true;
43
var index = 0;
44
var state = states[index];
45
var share = state.limit;
46
var instance = state.instance;
47
var storage = instance.storage;
48
var result = [ ];
49
var change = function() {
50
index += 1;
51
if (index >= states.length) {
52
index = 0;
53
}
54
state = states[index];
55
share = state.limit;
56
instance = state.instance;
57
storage = instance.storage;
58
};
59
var repeat = function() {
60
setTimeout(iterate);
61
};
62
var navigate = function() {
63
change();
64
repeat();
65
};
66
var complete = function() {
67
var count = Math.min(state.limit, storage.length, capacity - result.length);
68
if (count > 0) { // page is not completed yet
69
var slice = storage.splice(0, count);
70
for (var i = 0; i < slice.length; ++i) {
71
result.push(slice[i]);
72
}
73
if (result.length < capacity) {
74
share -= slice.length;
75
if (share > 0) {
76
return repeat();
77
}
78
return navigate();
79
}
80
}
81
processing = false;
82
return callback(result);
83
};
84
var iterate = function(){
85
var count = Math.min(state.limit, capacity - result.length);
86
if (count > storage.length) { // data should be fetch by additional request
87
var commit = function(data, disable) {
88
if (disable) {
89
remove(state.type);
90
}
91
if (data.length > 0) {
92
instance.offset += data.length;
93
for (var i = 0; i < data.length; ++i) {
94
storage.push({
95
type: state.type,
96
data: data[i]
97
});
98
}
99
complete();
100
} else {
101
navigate();
102
}
103
};
104
request(state.type, instance.offset, commit);
105
} else {
106
complete();
107
}
108
};
109
setTimeout(iterate);
110
return true;
111
};
112
}
113
114
// Example usage:
115
116
// We want to mix data following way:
117
// message picture picture picture video video
118
// message picture picture picture video video
119
// message picture picture picture video video
120
// etc.
121
122
var proportions = [
123
{ type: 'message', count: 1 },
124
{ type: 'picture', count: 3 },
125
{ type: 'video', count: 2 }
126
];
127
128
var request = function(type, offset, callback) {
129
console.log('REQUEST FOR: ' + type + 's');
130
//TODO: request with AJAX to proper link type and callback call
131
var response = [
132
{ id: offset + 0, name: 'Item name' },
133
{ id: offset + 1, name: 'Item name' },
134
{ id: offset + 2, name: 'Item name' },
135
{ id: offset + 3, name: 'Item name' },
136
{ id: offset + 4, name: 'Item name' },
137
{ id: offset + 5, name: 'Item name' }
138
];
139
callback(response);
140
};
141
142
var requester = new RequestMultiplexer(proportions, request );
143
144
function execute(counter) {
145
if (counter == 0) {
146
return;
147
}
148
var callback = function(response) {
149
// response contains combined data according to proportions
150
for (var i = 0; i < response.length; ++i) {
151
var item = response[i];
152
console.log('JOINED: ' + item.type + '-' + item.data.id + ' ' + item.data.name);
153
}
154
execute(counter - 1);
155
};
156
requester.request(callback);
157
}
158
159
execute(3);