;(function () {
'use strict';
var cache = {};
var promise = function (handler) {
var uuid = Number(String(Math.random()).slice(2)).toString(32);
cache[uuid] = {
then: [],
catch: []
};
var api = {
status: {
pending: true,
resolved: false,
rejected: false
},
queue: function (items, callback) {
var ready = promise();
var collection = [];
(function next(index) {
var item = callback(items[index], index, items);
if (!item) return;
item.then(function (data) {
collection[index] = data;
items[index + 1] ? next(index + 1) : ready.resolve(collection);
});
}(0));
return ready;
},
parallel: function (items, callback) {
var ready = promise();
var collection = [];
var counter = 0;
for (var i = 0; i < items.length; i++) {
(function (index) {
var item = callback(items[index], index, items);
if (!item) return;
item.then(function (data) {
counter++;
collection[index] = data;
if (items.length === counter) {
ready.resolve(collection);
}
});
}(i));
}
return ready;
},
all: function (promises) {
var ready = promise();
var collection = [];
var counter = 0;
for (var i = 0; i < promises.length; i++) {
(function (index) {
promises[index].then(function (data) {
counter++;
collection[index] = data;
if (promises.length === counter) {
ready.resolve(collection);
}
});
}(i));
}
return ready;
},
then: function (callback, data) {
if (api.status.resolved) {
callback(data);
} else {
cache[uuid].then.push(callback);
}
return api;
},
catch: function (callback, data) {
if (api.status.rejected) {
callback(data);
} else {
cache[uuid].catch.push(callback);
}
return api;
},
resolve: function (data) {
if (api.status.resolved) return api;
api.status.pending = false;
api.status.resolved = true;
for (var i = 0; i < cache[uuid].then.length; i++) {
api.then(cache[uuid].then[i], data);
}
return api;
},
reject: function (data) {
if (api.status.rejected) return api;
api.status.pending = false;
api.status.rejected = true;
for (var i = 0; i < cache[uuid].catch.length; i++) {
api.catch(cache[uuid].catch[i], data);
}
return api;
}
};
if (handler) {
var instanse = promise();
handler(instanse.resolve, instanse.reject);
return instanse;
} else {
return api;
}
};
window.promise = promise;
}());
(function () {
'use strict';
/** Одиночный AJAX запрос */
ajax('https://jsonplaceholder.typicode.com/posts/1').then(function (posts) {
console.log(posts);
});
/** Паралельные AJAX запросы */
promise().parallel([1, 2, 3, 4, 5, 6], function (id) {
return ajax(`https://jsonplaceholder.typicode.com/posts/${id}`);
}).then(function (posts) {
console.log(posts);
});
/** Последовательные AJAX запросы */
promise().queue([1, 2, 3, 4, 5, 6], function (id) {
return ajax(`https://jsonplaceholder.typicode.com/posts/${id}`);
}).then(function (posts) {
console.log(posts);
});
/** Использование promise. Пример 1 - callback функция */
getPostsMeta().then(function (posts) {
console.log(posts);
});
function getPostsMeta() {
return promise(function (resolve, reject) {
ajax('https://jsonplaceholder.typicode.com/posts').then(function (posts) {
var result = posts.map(function (post) {
return {
userId: post.userId,
postId: post.id
};
});
return resolve (result);
}).catch(function (error) {
return reject(error);
});
});
}
/** Использование promise. Пример 2 - создание инстанса */
wait(800).then(function (time) {
console.log(`Success async wait for ${time}ms`);
});
/** Версия с async/await */
(async () => {
const time = await wait(800);
console.log(`Success async wait for ${time}ms`);
})();
function wait(time) {
return promise(function (resolve) {
setTimeout(function () {
resolve(time);
}, time);
});
}
/** Async/Await с Thenable объектами */
(async () => {
var users = await ajax('https://jsonplaceholder.typicode.com/users');
console.log(users);
})();
/** Callback выполнения всех промисов */
var promises = [wait(500), wait(2500), wait(1000), wait(800)];
promise().all(promises).then(function (timers) {
console.log('All timers finished', timers);
});
// --------------------------------------------------------------------
function ajax(link) {
var ready = promise();
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status >= 200 & xhr.status < 400) {
var data = tryCatch(function () {
return JSON.parse(xhr.responseText);
}, xhr.responseText);
ready.resolve(data);
} else {
var error = {
status: xhr.status,
error: xhr.statusText
};
ready.reject(error);
}
};
xhr.onerror = function () {
var error = {
status: xhr.status,
error: xhr.statusText
};
ready.reject(error);
};
xhr.open('GET', link, true);
xhr.send();
return ready;
}
function tryCatch(done, fail) {
try {
if (typeof done === 'function') {
return done();
}
} catch (error) {
if (fail !== undefined) {
if (typeof fail === 'function') {
return fail(error);
} else {
return fail;
}
}
}
}
}());