Skip to content

Instantly share code, notes, and snippets.

@philipszdavido
Created August 22, 2018 09:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save philipszdavido/0317ccd9fef11e3384a02ecd0f88b3e4 to your computer and use it in GitHub Desktop.
Save philipszdavido/0317ccd9fef11e3384a02ecd0f88b3e4 to your computer and use it in GitHub Desktop.
let timers = [] // eg. setTimeout(...), setInterval(...)
let pending_callbacks = []
let idle = [] // eg. requestIdleCallback(...)
let prepare = []
let poll = [] //eg. HTTP conns, Socket conns, file ops
let check = [] // eg. setImmediate(...)
let close = [] // eg. socket.on('close',()=>{...})
let exit=[]
const log = console.log
var now = null
function removeFromArray(arr, index) {
// perf: array.pop is faster than array.splice!
if (index >= arr.length - 1) {
arr.pop();
} else {
arr.splice(index, 1);
}
}
function isEmpty(arr) {
return (arr.length <= 0) ? true : false
}
function is_loop_alive(){
if(
isEmpty(timers) &&
isEmpty(pending_callbacks)&&
isEmpty(idle)&&
isEmpty(prepare)&&
isEmpty(poll)&&
isEmpty(check)&&
isEmpty(close)
){
return false
}else{
return true
}
}
function call_exit(){
run_a_phase(exit)
}
function checkTimers(timers) {
for (let i = 0; i < timers.length; i++) {
const { callback, ms } = timers[i]
const _now = Date.now()
if ((ms + now) <= _now) {
return true
}
}
return false
}
function waitForCallbacks(){
/* poll will try to wait a bit, but with certain conditions.
* If there is any task pending in check queue, pending queue or closing callbacks queue (idle handlers queue as well), it will
* wait for zero milliseconds.
*/
}
function run_a_phase(phase){
for (let i = 0; i < phase.length; i++) {
phase[i]()
removeFromArray(phase, i)
}
}
const _setTimeout = function(callback, ms) {
timers.push({
ms,
callback
})
timers.sort((a,b)=>a-b)
}
const _setImmediate = function(cb) {
check.push(cb)
}
const socket_on_close = function(cb) {
close.push(cb)
}
/** phase functions here */
function run_timers_phase() {
if(!now){
now = Date.now()
}
//const now = Date.now()
//while (timers.length > 0) {
for (let i = 0; i < timers.length; i++) {
const { callback, ms } = timers[i]
const _now = Date.now()
if ((ms + now) <= _now) {
callback()
removeFromArray(timers, i)
}
}
//}
}
function run_pending_callbacks_phase() {
run_a_phase(pending_callbacks)
}
function run_idle_phase() {
run_a_phase(idle)
}
function run_prepare_phase() {
run_a_phase(prepare)
}
function run_poll_phase() {
const SYSTEM_HARD_LIMIT = 100
//If the poll queue is not empty
if (!isEmpty(poll)) {
//iterate through its queue of callbacks executing them synchronously
for (var index = 0; index < poll.length; index++) {
poll[index]();
removeFromArray(poll, index)
if (index == SYSTEM_HARD_LIMIT) {
break;
}
}
}
//If the poll queue is empty
else {
//If scripts have been scheduled by setImmediate() ,
if (!isEmpty(check)) {
//end the poll phase and continue to the check phase to execute those scheduled scripts
return run_check_phase()
}
//If scripts have not been scheduled by setImmediate()
else {
//wait for callbacks to be added to the queue, then execute them immediately.
waitForCallbacks()
}
}
//check for timers whose time thresholds have been reached.
if(checkTimers(timers)){
run_timers_phase()
}
}
function run_check_phase() {
run_a_phase(check)
}
function run_close_phase() {
run_a_phase(close)
}
function main() {
while(is_loop_alive()){
run_timers_phase()
run_pending_callbacks_phase()
run_idle_phase()
run_prepare_phase()
run_poll_phase()
run_check_phase()
run_close_phase()
}
call_exit()
}
/*setTimeout(()=>{
log('1000 ms')
},1000)
setTimeout(()=>{
log('1000000 ms')
},10)
run_timers_phase()
*/
_setTimeout(() => {
log('0 ms')
},0)
_setImmediate(()=>{log('ImmediateI')})
_setTimeout(() => {
log('1 ms')
}, 1)
_setTimeout(() => {
log('100 ms')
}, 100)
_setTimeout(() => {
log('200 ms')
}, 200)
_setImmediate(()=>{log('ImmediateII')})
_setTimeout(() => {
log('300 ms')
}, 300)
_setTimeout(() => {
log('400 ms')
}, 400)
main()
return
setTimeout(() => {
log('0 ms')
},0)
setImmediate(()=>{log('ImmediateI')})
setTimeout(() => {
log('1 ms')
}, 1)
setTimeout(() => {
log('2 ms')
}, 2)
setTimeout(() => {
log('3 ms')
}, 3)
setTimeout(() => {
log('100 ms')
}, 100)
setTimeout(() => {
log('200 ms')
}, 200)
setImmediate(()=>{log('ImmediateII')})
setTimeout(() => {
log('300 ms')
}, 300)
setTimeout(() => {
log('400 ms')
}, 400)
/*
0 ms
1 ms
ImmediateI
ImmediateII
100 ms
200 ms
300 ms
400 ms
*/
return
/*0 ms
ImmediateI
ImmediateII
100 ms
200 ms
300 ms
400 ms
*/
//run_timers_phase()
/*
function run_timers_phase() {
const now = Date.now()
while (timers.length > 0) {
for (let i = 0; i < timers.length; i++) {
const { callback, ms } = timers[i]
const _now = Date.now()
if ((ms + now) <= _now) {
callback()
removeFromArray(timers, i)
}
}
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment