Skip to content

Instantly share code, notes, and snippets.

@Ariex
Last active February 17, 2022 07:31
Show Gist options
  • Save Ariex/e6dd7916bf0004bf18a0d62a669caf07 to your computer and use it in GitHub Desktop.
Save Ariex/e6dd7916bf0004bf18a0d62a669caf07 to your computer and use it in GitHub Desktop.
Promise.allInOrder
// v3 is shorter than v2, and achieve same goal
(()=>{
let Deferred = function(){
let resolver, rejector,
promise = new Promise((resolve, reject)=>{
resolver = resolve;
rejector = reject;
});
promise.resolve = d=>resolver(d);
promise.reject = d=>rejector(d);
return promise;
};
// the idea of this function is, setup a continuous task that will be executed by each of the previous task in order.
// for example, if there are 3 previous tasks, task[2] finished, the continuous task will not be executed, then task[1] finished, the continuous task will be executed for task[1] then task[2] in order, then task[3] finished, the continuous task will executed for task[3]
Promise.allInOrder = (...promises)=>{
// this thenForEachFunc could be invoked when there is no func been set, and func will be called in order immidiately when it been set with a value
// to achieve this, we make invoke an async function, so it will only return value when func have valid value. If func is null, then create a deferred object then push to a queue, which this queue will be processed when setFunc been called, to make sure the async invoke function will be resolved eventually.
let thenForEachFunc = (function(){
let func = null;
let promiseToExecuteFunc = new Array(promises.length);
return {
setFunc: _func=>{
func = _func;
for(let i=0,l=promiseToExecuteFunc.length;i<l;i++){
if(promiseToExecuteFunc[i]===void(0)){
return;
}else if(promiseToExecuteFunc[i]!==null){
let d = promiseToExecuteFunc[i];
d.resolve(func);
promiseToExecuteFunc[i] = null;
}
}
},
invoke: async function(data, index){
let promiseToGetResult = new Promise((resolve, reject)=>{
let deferred = new Deferred();
deferred.then(func=>resolve(func.call(null, ...arguments)));
// to make sure the callback function will be executed in order, we put it in a queue, which will be processed in order
// also since js is single thread, so the chance that adding a new element to queu when queue is processing is not possible, whenever calling "invoke" method, it will have to happen after previous setFunc function.
promiseToExecuteFunc[index]=deferred;
});
this.setFunc(func);
return promiseToGetResult;
}
};
})();
let anotherPromise = promises.map((p, i)=>{
return promises[i].then(d=>{
return new Promise(async(resolve, reject)=>{
let result = await thenForEachFunc.invoke(d, i);
resolve(result);
});
});
}
);
return {
thenForEach: thenForEachCallback => {
thenForEachFunc.setFunc(thenForEachCallback);
return {
all: func=>{
Promise.all(anotherPromise).then(d=>func(d));
}
}
}
}
};
})();
/* Promise
.allInOrder(promise1, promise2, promise3)
.thenForEach(d=>console.log(d))
.catchForEach(err=>{}) //<== not support yet, but should not be hard to add
.all((...d)=>console.log(d));
*/
(()=>{
let timeConsumingFunc = param=>new Promise(
(resolve)=>{
let timeout = Math.random() * 5000;
console.log(`task ${param} will be resolved in ${timeout}ms`);
setTimeout(()=>{
console.log(`${param} resolved`);
resolve(param+10);
}, timeout);
}
);
Promise
.allInOrder(timeConsumingFunc(1), timeConsumingFunc(2), timeConsumingFunc(3))
.thenForEach(d=>{
console.log(d);
return d+20;
})
.all(ds=>{
console.log(`all method called`);
console.log(ds);
})
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment