Related
I Have 3 Function and each one work with Promise.resolve Invidualy,
How Can use Promise.resolve For All?, When I Call All Functions, Those Aren't Ordered
function sendAllText(msg, opts) {
if (locale.keyboards[msg.text].text) {
var i,j,tempstring, promise;
promise = Promise.resolve();
for (i=0,j=locale.keyboards[msg.text].text.length; i<j; i++) {
tempstring = locale.keyboards[msg.text].text[i];
promise = promise.then(bot.sendMessage.bind(bot,msg.chat.id, tempstring, opts));
}
}
}
function sendAllPhoto(msg, opts) {
if (locale.keyboards[msg.text].photo) {
var i,j,tempstring, promise;
promise = Promise.resolve();
for (i=0,j=locale.keyboards[msg.text].photo.length; i<j; i++) {
tempstring = locale.keyboards[msg.text].photo[i];
promise = promise.then(bot.sendPhoto.bind(bot,msg.chat.id, tempstring, opts));
}
}
}
function sendAllVideo(msg, opts) {
if (locale.keyboards[msg.text].video) {
var i,j,tempstring, promise;
promise = Promise.resolve();
for (i=0,j=locale.keyboards[msg.text].video.length; i<j; i++) {
tempstring = locale.keyboards[msg.text].video[i];
promise = promise.then(bot.sendVideo.bind(bot,msg.chat.id, tempstring, opts));
}
}
}
When I call Functions, My Data is not Ordered, I'm Using Node telegram bot Api
bot.onText(/\/love/, function onLoveText(msg) {
const opts = {
reply_to_message_id: msg.message_id,
reply_markup: JSON.stringify({
keyboard: [
['Yes, you are the bot of my life ❤'],
['No, sorry there is another one...']
]
})
};
sendAllText(msg, opts);
sendAllPhoto(msg, opts);
sendAllVideo(msg, opts);
});
At the end of each of the three functions, right after their loops, add:
return promise;
Also make sure you define the promise variable at the start of the function, so it also is defined when the if condition is not true.
For example, in the first function:
function sendAllText(msg, opts) {
var promise = Promise.resolve(); // <----
if (locale.keyboards[msg.text].text) {
var i,j,tempstring;
for (i=0,j=locale.keyboards[msg.text].text.length; i<j; i++) {
tempstring = locale.keyboards[msg.text].text[i];
promise = promise.then(bot.sendMessage.bind(bot,msg.chat.id, tempstring, opts));
}
}
return promise; // <-----
}
Then in the last piece of code, chain your promises:
sendAllText(msg, opts)
.then(sendAllPhoto.bind(null, msg, opts))
.then(sendAllVideo.bind(null, msg, opts));
You can use $q.all, The $q.all() method takes either an object or an array of promises and waits for all of them to resolve() or one of them to reject() and then executes the provided callback function. The values returned from the resolve function are provided depending on the way you give the promises to all().
Example -
var promises = [sendAllText(), sendAllPhoto(), sendAllVideo()];
$q.all(promises).then((values) => {
console.log(values[0]); // value Text
console.log(values[1]); // value Photo
console.log(values[2]); // value Video
});
I'm kicking off a nested promise mapping and seeing the outer .then() block print a null result before the resolve in the function is called.
I feel like I must be messing up the syntax somehow. I've made this stripped down example:
const Promise = require('bluebird');
const topArray = [{outerVal1: 1,innerArray: [{innerVal1: 1,innerVal2: 2}, {innerVal1: 3,innerVal2: 4}]},{outerVal2: 2,innerArray: [{innerVal1: 5, innerVal2: 6 }, {innerVal1: 7,innerVal2: 8 }]}] ;
promiseWithoutDelay = function (innerObject) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("promiseWithDelay" ,innerObject);
let returnVal = {}
returnVal.innerVal1 = innerObject.innerVal1;
returnVal.innerVal2 = innerObject.innerVal2;
returnVal.delay = false;
return resolve(returnVal);
}, 0);
})
}
promiseWithDelay = function (innerObject) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("promiseWithDelay" ,innerObject);
let returnVal = {}
returnVal.innerVal1 = innerObject.innerVal1;
returnVal.innerVal2 = innerObject.innerVal2;
returnVal.delay = true;
return resolve(returnVal);
}, 3000);
})
}
test1 = function () {
let newArray = [];
let newArrayIndex = 0;
Promise.map(topArray, function (outerObject) {
Promise.map(outerObject.innerArray, function (innerObject) {
Promise.all([
promiseWithoutDelay(innerObject),
promiseWithDelay(innerObject)
])
.then(function (promiseResults) {
newArray[newArrayIndex++] = {result1: promiseResults[1], result2: promiseResults[2]}
})
})
})
.then(function () {
return newArray;
})
}
var result = test1();
console.log("got result ",result);
What I'm trying to do is loop over an outer array that has some values that I need.
These values include a nested inner array that I must also loop over to get some values.
In the inner loop I pass the outer and inner values to promise functions in a Promise.all.
When the promise functions resolve they get assigned to a return object.
It seems to be working fine except for one of the promise functions sometimes has a delay as it's doing some calculations.
When this happens it is left out of the return value because it hasn't resolved yet.
Shouldn't it wait until the inner loop with Promise.all resolves before it returns from the outer loop?
Can you point me in the right direction?
EDIT: Ended up with this solution based on #Thomas's suggestion:
test1 = function(){
return Promise.map(topArray, function(outerObject){
let oVal = outerObject.outerVal;
return Promise.map(outerObject.innerArray, function(innerObject){
innerObject.oVal = oVal;
return Promise.all([ promiseWithDelay(innerObject), promiseWithoutDelay(innerObject)])
.then(function(results) {
return { result1: results[0], result2: results[1], delay: results[2] } ;
})
})
}).reduce(function(newArray, arr){
return newArray.concat(arr);
}, []);
}
I'm not entirely sure I get your problem from your stripped down example, but I think what you want to do here is this:
test1 = function(){
return Promise.map(topArray, function(outerObject){
return Promise.all(outerObject.innerArray)
}).reduce(function(newArray, arr){
return newArray.concat(arr);
}, []);
}
How do you go about knowing when a For Loop is done iterating and attach a callback.
This is a sample loop of many loops within a function that inserts records into indexedDB.
if (Object.hasOwnProperty("Books")) {
for (var i = 0, j = Object["Books"].length; i < j; i++) {
server.Book.add({
title: Object["Books"][i].Cat,
content: Object["Books"][i]
});
}
}
I need to be able to know when each of the if statements loops are finished then attach a callback. All the loops are being fired asynchronously, and I need to run a function_final() just when all loops are finished not when they are fired.
EDIT
What I have tried so far :
InsertDB = {
addBook: function(Object) {
return $.Deferred(function() {
var self = this;
setTimeout(function() {
if (Object.hasOwnProperty("Book")) {
for (var i = 0, j = Object["Book"].length; i < j; i++) {
server.Book.add({
title: Object["Book"][i].id,
content: Object["Book"][i]
});
}
self.resolve();
}
}, 200);
});
},
addMagaz: function(Object) {
return $.Deferred(function() {
var self = this;
setTimeout(function() {
if (Object.hasOwnProperty("Magaz")) {
for (var i = 0, j = Object["Magaz"].length; i < j; i++) {
server.Magaz.add({
content: Object["Magaz"][i]
});
}
self.resolve();
}
}, 2000);
});
},
addHgh: function(Object) {
return $.Deferred(function() {
var self = this;
setTimeout(function() {
if (Object.hasOwnProperty("MYTVhighlights")) {
for (var i = 0, j = Object["MYTVhighlights"].length; i < j; i++) {
server.MYTVhighlights.add({
content: Object["MYTVhighlights"][i]
});
}
self.resolve();
}
}, 200);
});
}, ect...
then on a AJAX success callback :
success: function(data){
var Object = $.parseJSON(data);
$.when(InsertDB.addBook(Object),
InsertDB.addMagaz(Object),
InsertDB.addUser(Object),
InsertDB.addArticles(Object),
InsertDB.addHgh(Object),
InsertDB.addSomeC(Object),
InsertDB.addOtherC(Object)).done(final_func);
function final_func() {
window.location = 'page.html';
}
Here final_func is fired before looping ends..
Thanks
You can use JavaScript closures, just like this:
if (Object.hasOwnProperty("Books")) {
for (var i = 0, j = Object["Books"].length; i < j; i++) {
(function(currentBook)
server.Book.add({
title: currentBook.Cat,
content: currentBook
});
)(Object["Books"][i]);
}
function_final();
}
For more information about closures you can refer here.
Since you've said that server.Book.add() is asynchronous, you will need a method of knowing when that asynchronous operation is completed and you can then use that to build a system for knowing when all of them are done. So, the pivotal question (which I already asked as a comment earlier and you have not responded to) is how you can know when server.Book.add() is actually complete. If you're using an indexedDB, then somewhere inside that function, there is probably a request object that has an onsuccess and onerror methods that will tell you when that specific operation is done and that information needs to get surfaced out to server.Book.add() in some way, either as a completion callback or as a returned promise (those two options are how $.ajax() operates for it's asynchronous behavior.
Let's suppose that server.Book.add() returns a promise object that is resolved or rejected when the asychronous .add() operation is complete. If that was the case, then you could monitor the completion of all the operations in your loop like this:
if (obj.hasOwnProperty("Books")) {
var promises = [], p;
for (var i = 0, j = obj["Books"].length; i < j; i++) {
p = server.Book.add({
title: obj["Books"][i].Cat,
content: obj["Books"][i]
});
promises.push(p);
}
$.when.apply($, promises).done(function() {
// this is executed when all the promises returned by
// server.Book.add() have been resolved (e.g. completed)
}).error(function() {
// this is executed if any of the server.Book.add() calls
// had an error
});
}
Let's suppose that instead of server.Book.add() returning a promise, it has a couple callbacks for success and error conditions. Then, we could write the code like this:
if (obj.hasOwnProperty("Books")) {
var promises = [], p;
for (var i = 0, j = obj["Books"].length; i < j; i++) {
(function() {
var d = $.Deferred();
server.Book.add({
title: obj["Books"][i].Cat,
content: obj["Books"][i],
success: function() {
var args = Array.prototype.slice.call(arguments, 0);
d.resolve.apply(d, args);
},
error: function() {
var args = Array.prototype.slice.call(arguments, 0);
d.reject.apply(d, args);
}
});
promises.push(d.promise());
})();
}
$.when.apply($, promises).done(function() {
// this is executed when all the promises returned by
// server.Book.add() have been resolved (e.g. completed)
}).error(function() {
// this is executed if any of the server.Book.add() calls
// had an error
});
}
So, since you've not disclosed how server.Book.add() actually indicates its own completion, I can't say that either of these blocks of code work as is. This is meant to demonstrate how you solve this problem once you know how server.Book.add() communicates when it is complete.
Promises/Deferreds are not magic in any way. They don't know when an operation is completed unless that operation calls .resolve() or .reject() on a promise. So, in order to use promises, your async operations have to participate in using promises or you have to shim in a promise to an ordinary completion callback (as I've done in the second code block).
FYI, I also change your Object variable to obj because defining a variable named Object that conflicts with the built-in Object in the javascript language is a bad practice.
use jquery when functionality
$.when( function1 , function2 )
.then( myFunc, myFailure );
I'd write something like this in pure JS, consider it as pseudo code:
var totalForLoopsCount = 3; //Predict for loops count here
var forLoopsFinished = 0;
function finalFunction()
{
alert('All done!');
}
function forLoopFinished()
{
forLoopsFinished++;
if(forLoopsFinished == totalForLoopsCount)
{
finalFunction();
}
}
var length = 10; //The length of your array which you're iterating trough
for(var i=0;i<length;i++)
{
//Do anything
if(i == length-1)
{
forLoopFinished();
}
}
for(var i=0;i<length;i++)
{
//Do anything
if(i == length-1)
{
forLoopFinished();
}
}
for(var i=0;i<length;i++)
{
//Do anything
if(i == length-1)
{
forLoopFinished();
}
}
I am using the Q javascript promises library and am running in a browser, and I want to figure out how to chain together groups of promises so that each group gets executed sequentially. For example, if I have items A, B, C, and D, I want to group A and B together and then C and D together, so that both A and B must fulfill before C and D get executed. I created this simple jsfiddle to show my current attempt.
var work_items = [ 'A','B','C','D','E','F','G','H','I' ];
var n = 2; // group size
var wait = 1000;
var getWorkPromiseFn = function (item) {
log("Getting promise function for " + item);
return function () {
log("Starting " + item);
var deferred = Q.defer();
setTimeout(function () {
var status = "Finished " + item;
log(status);
deferred.resolve(status);
}, wait);
return deferred.promise;
};
};
var queue = Q();
//log('Getting sequentially'); // One-by-one in sequence works fine
//work_items.forEach(function (item) {
// queue = queue.then(getWorkPromiseFn(item));
//});
log('Getting ' + n + ' at a time'); // This section does not
while (work_items.length > 0) {
var unit = [];
for (var i=0; i<n; i++) {
var item = work_items.shift();
if (item) {
unit.push(getWorkPromiseFn(item));
}
}
queue.then(Q.all(unit));
}
var inspect = queue.inspect(); // already fulfilled, though no work is done
It looks like I am probably passing the wrong array to Q.all here, since I'm passing in an array of functions which return promises rather than an array of the promises themselves. When I tried to use promises directly there (with unit.push(Q().then(getWorkPromiseFn(item)); for example), the work for each was begun immediately and there was no sequential processing. I guess I'm basically unclear on a good way to represent the group in a way that appropriately defers execution of the group.
So, how can I defer execution of a group of promises like this?
This can be done by first pre-processing the array of items into groups, then applying the two patterns (not the anti-patterns) provided here under the heading "The Collection Kerfuffle".
The main routine can be coded as a single chain of array methods.
var work_items = [ 'A','B','C','D','E','F','G','H','I' ];
var wait = 3000;
//Async worker function
function getWorkPromise(item) {
console.log("Starting " + item);
var deferred = Q.defer();
setTimeout(function () {
var status = "Finished " + item;
console.log(status);
deferred.resolve(status);
}, wait);
return deferred.promise;
};
function doAsyncStuffInGroups(arr, n) {
/*
* Process original array into groups, then
* process the groups in series,
* progressing to the next group
* only after performing something asynchronous
* on all group members in parallel.
*/
return arr.map(function(currentValue, i) {
return (i % n === 0) ? arr.slice(i, i+n) : null;
}).filter(function(item) {
return item;
}).reduce(function(promise, group) {
return promise.then(function() {
return Q.all(group.map(function(item) {
return getWorkPromise(item);
}));
});
}, Q());
}
doAsyncStuffInGroups(work_items, 2).then(function() {
console.log("All done");
});
See fiddle. Delay of 3s gives you time to appreciate what's going on. I found 1s too quick.
Solutions like this are elegant and concise but pretty well unreadable. In production code I would provide more comments to help whoever came after me.
For the record:
The opening arr.map(...).filter(...) processes arr (non destructively) into an array of arrays, each inner array representing a group of length n (plus terminal remainders).
The chained .reduce(...) is an async "serializer" pattern.
The nested Q.all(group.map(...)) is an async "parallelizer" pattern.
The .then function of a promise does not mutate the promise, so when you do:
p.then(function(){
// stuff
});
You do not change the promise p at all, instead, you need to assign it to something:
p = p.then(....)
This is why your queue promise was always resolved, it never changed beyond Q().
In your case, something like changing:
queue.then(Q.all(unit));
Into:
queue = queue.then(function(){ return Q.all(unit); });
Or in ES6 promises and libraries that use their syntax like Bluebird the other answer mentioned:
queue = queue.then(function(){ return Promise.all(unit); });
The thing that confused me most is that the async function being chained needs to return a function that returns a promise. Here's an example:
function setTimeoutPromise(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
function foo(item, ms) {
return function() {
return setTimeoutPromise(ms).then(function () {
console.log(item);
});
};
}
var items = ['one', 'two', 'three'];
function bar() {
var chain = Promise.resolve();
for (var i in items) {
chain = chain.then(foo(items[i], (items.length - i)*1000));
}
return chain.then();
}
bar().then(function () {
console.log('done');
});
Notice that foo returns a function that returns a promise. foo() does not return a promise directly.
See this Live Demo
i would suggest you use bluebird, its the best performance promise out there, https://github.com/petkaantonov/bluebird
the example to chain should also be here https://github.com/petkaantonov/bluebird#how-do-long-stack-traces-differ-from-eg-q
I've looked at many implementations and they all look so different I can't really distill what the essence of a promise is.
If I had to guess it is just a function that runs when a callback fires.
Can someone implement the most basic promise in a few lines of code w/ out chaining.
For example from this answer
Snippet 1
var a1 = getPromiseForAjaxResult(ressource1url);
a1.then(function(res) {
append(res);
return a2;
});
How does the function passed to then know when to run.
That is, how is it passed back to the callback code that ajax fires on completion.
Snippet 2
// generic ajax call with configuration information and callback function
ajax(config_info, function() {
// ajax completed, callback is firing.
});
How are these two snippets related?
Guess:
// how to implement this
(function () {
var publik = {};
_private;
publik.then = function(func){
_private = func;
};
publik.getPromise = function(func){
// ??
};
// ??
}())
Fundamentally, a promise is just an object that has a flag saying whether it's been settled, and a list of functions it maintains to notify if/when it is settled. Code can sometimes say more than words, so here's a very basic, not-real-world example purely indended to help communicate the concepts:
// See notes following the code for why this isn't real-world code
function Promise() {
this.settled = false;
this.settledValue = null;
this.callbacks = [];
}
Promise.prototype.then = function(f) {
if (this.settled) {
f(this.settledValue); // See notes 1 and 2
} else {
this.callbacks.push(f);
}
// See note 3 about `then`
// needing a return value
};
Promise.prototype.settle = function(value) { // See notes 4 and 5
var callback;
if (!this.settled) {
this.settled = true;
this.settledValue = value;
while (this.callbacks.length) {
callback = this.callbacks.pop();
callback(this.settledValue); // See notes 1 and 2
}
}
};
So the Promise holds the state, and the functions to call when the promise is settled. The act of settling the promise is usually external to the Promise object itself (although of course, that depends on the actual use, you might combine them — for instance, as with jQuery's ajax [jqXHR] objects).
Again, the above is purely conceptual and missing several important things that must be present in any real-world promises implementation for it to be useful:
then and settle should always call the callback asynchronously, even if the promise is already settled. then should because otherwise the caller has no idea whether the callback will be async. settle should because the callbacks shouldn't run until after settle has returned. (ES2015's promises do both of these things. jQuery's Deferred doesn't.)
then and settle should ensure that failure in the callback (e.g., an exception) is not propagated directly to the code calling then or settle. This is partially related to #1 above, and more so to #3 below.
then should return a new promise based on the result of calling the callback (then, or later). This is fairly fundamental to composing promise-ified operations, but would have complicated the above markedly. Any reasonable promises implementation does.
We need different types of "settle" operation: "resolve" (the underlying action succeeded) and "reject" (it failed). Some use cases might have more states, but resolved and rejected are the basic two. (ES2015's promises have resolve and reject.)
We might make settle (or the separate resolve and reject) private in some way, so that only the creator of the promise can settle it. (ES2015 promises — and several others — do this by having the Promise constructor accept a callback that receives resolve and reject as parameter values, so only code in that callback can resolve or reject [unless code in the callback makes them public in some way].)
Etc., etc.
Can someone implement the most basic promise in a few lines?
Here it is:
function Promise(exec) {
// takes a function as an argument that gets the fullfiller
var callbacks = [], result;
exec(function fulfill() {
if (result) return;
result = arguments;
for (let c;c=callbacks.shift();)
c.apply(null, arguments);
});
this.addCallback = function(c) {
if (result)
c.apply(null, result)
else
callbacks.push(c);
}
}
Additional then with chaining (which you will need for the answer):
Promise.prototype.then = function(fn) {
return new Promise(fulfill => {
this.addCallback((...args) => {
const result = fn(...args);
if (result instanceof Promise)
result.addCallback(fulfill);
else
fulfill(result);
});
});
};
How are these two snippets related?
ajax is called from the getPromiseForAjaxResult function:
function getPromiseForAjaxResult(ressource) {
return new Promise(function(callback) {
ajax({url:ressource}, callback);
});
}
I've implement one in ES7. With chaining, it's 70 lines, if that counts as few. I think State Machine is the right paradigm for implementing promises. Resulting code is more understandable than lots of ifs IMHO. Described fully in this article.
Here's the code:
const states = {
pending: 'Pending',
resolved: 'Resolved',
rejected: 'Rejected'
};
class Nancy {
constructor(executor) {
const tryCall = callback => Nancy.try(() => callback(this.value));
const laterCalls = [];
const callLater = getMember => callback => new Nancy(resolve => laterCalls.push(() => resolve(getMember()(callback))));
const members = {
[states.resolved]: {
state: states.resolved,
then: tryCall,
catch: _ => this
},
[states.rejected]: {
state: states.rejected,
then: _ => this,
catch: tryCall
},
[states.pending]: {
state: states.pending,
then: callLater(() => this.then),
catch: callLater(() => this.catch)
}
};
const changeState = state => Object.assign(this, members[state]);
const apply = (value, state) => {
if (this.state === states.pending) {
this.value = value;
changeState(state);
for (const laterCall of laterCalls) {
laterCall();
}
}
};
const getCallback = state => value => {
if (value instanceof Nancy && state === states.resolved) {
value.then(value => apply(value, states.resolved));
value.catch(value => apply(value, states.rejected));
} else {
apply(value, state);
}
};
const resolve = getCallback(states.resolved);
const reject = getCallback(states.rejected);
changeState(states.pending);
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
static resolve(value) {
return new Nancy(resolve => resolve(value));
}
static reject(value) {
return new Nancy((_, reject) => reject(value));
}
static try(callback) {
return new Nancy(resolve => resolve(callback()));
}
}
Here's a light-weight promise implementation, called 'sequence', which I use in my day-to-day work:
(function() {
sequence = (function() {
var chained = [];
var value;
var error;
var chain = function(func) {
chained.push(func);
return this;
};
var execute = function(index) {
var callback;
index = typeof index === "number" ? index : 0;
if ( index >= chained.length ) {
chained = [];
return true;
}
callback = chained[index];
callback({
resolve: function(_value) {
value = _value;
execute(++index);
},
reject: function(_error) {
error = _error;
execute(++index);
},
response: {
value: value,
error: error
}
});
};
return {
chain: chain,
execute: execute
};
})();
})();
Once initialized, you can use sequence in the following way:
sequence()
.chain(function(seq) {
setTimeout(function() {
console.log("func A");
seq.resolve();
}, 2000);
})
.chain(function(seq) {
setTimeout(function() {
console.log("func B");
}, 1000)
})
.execute()
To enable the actual chaining, you need to call the resolve() function of the seq object, which your callbacks must use as an argument.
Sequence exposes two public methods:
chain - this method simply pushes your callbacks to a private array
execute - this method uses recursion to enable the proper sequential execution of your callbacks. It basically executes your callbacks in the order you've chained them by passing the seq object to each of them. Once the current callback is resolved/rejected, the next callback is executed.
The 'execute' method is where the magic happens. It passes the 'seq' object to all of your callbacks. So when you call seq.resolve() or seq.reject() you'll actually call the next chained callback.
Please, note that this implementation stores a response from only the previously executed callback.
For more examples and documentation, please refer to:
https://github.com/nevendyulgerov/sequence
Here is a simple Promise implementation that works for me.
function Promise(callback) {
this._pending = [];
this.PENDING = "pending";
this.RESOLVED = "resolved";
this.REJECTED = "rejected";
this.PromiseState = this.PENDING;
this._catch = function (error) {
console.error(error);
};
setTimeout(function () {
try {
callback.call(this, this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}.bind(this), 0)
};
Promise.prototype.resolve = function (object) {
if (this.PromiseState !== this.PENDING) return;
while (this._pending.length > 0) {
var callbacks = this._pending.shift();
try {
var resolve = callbacks.resolve;
if (resolve instanceof Promise) {
resolve._pending = resolve._pending.concat(this._pending);
resolve._catch = this._catch;
resolve.resolve(object);
return resolve;
}
object = resolve.call(this, object);
if (object instanceof Promise) {
object._pending = object._pending.concat(this._pending);
object._catch = this._catch;
return object;
}
} catch (error) {
(callbacks.reject || this._catch).call(this, error);
return;
}
}
this.PromiseState = this.RESOLVED;
return object;
};
Promise.prototype.reject = function (error) {
if (this.PromiseState !== this.PENDING) return;
this.PromiseState = this.REJECTED;
try {
this._catch(error);
} catch (e) {
console.error(error, e);
}
};
Promise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = onFulfilled || function (result) {
return result;
};
this._catch = onRejected || this._catch;
this._pending.push({resolve: onFulfilled, reject: onRejected});
return this;
};
Promise.prototype.catch = function (onRejected) {
// var onFulfilled = function (result) {
// return result;
// };
this._catch = onRejected || this._catch;
// this._pending.push({resolve: onFulfilled, reject: onRejected});
return this;
};
Promise.all = function (array) {
return new Promise(function () {
var self = this;
var counter = 0;
var finishResult = [];
function success(item, index) {
counter++;
finishResult[index] = item;
if (counter >= array.length) {
self.resolve(finishResult);
}
}
for(var i in array) {
var item = array[i];
if (item instanceof Promise) {
item.then(function (result) {
success(result,this);
}.bind(i), function (error) {
array.map(function (item) {
item.PromiseState = Promise.REJECTED
});
self._catch(error);
})
} else {
success(item, i);
}
}
});
};
Promise.race = function (array) {
return new Promise(function () {
var self = this;
var counter = 0;
var finishResult = [];
array.map(function (item) {
if (item instanceof Promise) {
item.then(function (result) {
array.map(function (item) {
item.PromiseState = Promise.REJECTED
});
self.resolve(result);
}, function (error) {
array.map(function (item) {
item.PromiseState = Promise.REJECTED
});
self._catch(error);
})
} else {
array.map(function (item) {
item.PromiseState = Promise.REJECTED
});
self.resolve(item);
}
})
});
};
Promise.resolve = function (value) {
return new Promise(function (resolve, reject) {
try {
resolve(value);
} catch (error) {
reject(error);
}
});
};
Promise.reject = function (error) {
return new Promise(function (resolve, reject) {
reject(error);
});
}
Discussing here.
Fiddle: here.
here is the absolute minimum of a promise architecture
function Promise(F) {
var gotoNext = false;
var stack = [];
var args = [];
var isFunction = function(f) {
return f && {}.toString.call(f) === '[object Function]';
};
var getArguments = function(self, _args) {
var SLICE = Array.prototype.slice;
_args = SLICE.call(_args);
_args.push(self);
return _args;
};
var callNext = function() {
var method = stack.shift();
gotoNext = false;
if (isFunction(method)) method.apply(null, args);
};
var resolve = [(function loop() {
if (stack.length) setTimeout(loop, 0);
if (gotoNext) callNext();
})];
this.return = function() {
gotoNext = true;
args = getArguments(this, arguments);
if(resolve.length) resolve.shift()();
return this;
};
this.then = function(fn) {
if (isFunction(fn)) stack.push(fn);
return this;
};
return this.then(F).return();
}
// --- below is a working implementation --- //
var bar = function(p) {
setTimeout(function() {
console.log("1");
p.return(2);
}, 1000);
};
var foo = function(num, p) {
setTimeout(function() {
console.log(num);
p.return(++num);
}, 1000);
};
new Promise(bar)
.then(foo)
.then(foo)
.then(foo);