浏览器主进程渲染进程就是我们说的浏览器内核网络进程 处理网络请求、文件访问等操作(function mainThread() {
    let task1 = 1 + 2;
    let task2 = 2 + 3;
    let task3 = 3 + 4;
    console.log(task1, task2, task3);
})()
let readline = require('readline-sync');
(function mainThread() {
    while (true) {
        var num1 = readline.question('num1: ');
        var num2 = readline.question('num2: ');
        let ret = eval(num1 + "+" + num2);
        console.log(ret);
    }
})();

class MessageQueue {
    constructor() {
        this.messages = [];
    }
    put(message) {
        this.messages.push(message);
    }
    get() {
        return this.messages.pop();
    }
}
module.exports = new MessageQueue();
const messageQueue = require('./messageQueue');
(function mainThread() {
    setInterval(() => {
        let task = messageQueue.get();
        if (task) task();
    }, 1000);
})();
(function IOThread() {
    let counter = 1;
    setInterval(() => {
        messageQueue.put(()=>console.log(`task` + counter++));
    }, 1000);
})();

render.js
const { fork } = require('child_process');
const messageQueue = require('./messageQueue');
(function mainThread() {
    setInterval(() => {
        let task = messageQueue.get();
        if (task) task();
    }, 1000);
})();
(function IOThread() {
    let browser = fork('./browser.js');
    browser.on('message', function ({ data }) {
        messageQueue.put(() => {
            console.log(data);
        });
    });
    browser.send({ type: 'click', data: 'clicked' });
})();
process.on('message', function ({ data }) {
  setTimeout(() => {
      process.send({ data });
  }, 100);
});
render.js
const { fork } = require('child_process');
+const { macroTaskQueue, microTaskQueue } = require('./messageQueue');
(function mainThread() {
    setInterval(() => {
+       let macroTask = macroTaskQueue.get();
+       if (macroTask) macroTask();
+       let microTask;
+       while (microTask = microTaskQueue.get()) {
+           microTask();
+       }
    }, 1000);
})();
(function IOThread() {
    let browser = fork('./browser.js');
    browser.on('message', function ({ data }) {
        macroTaskQueue.put(() => {
            console.log(data);
+           microTaskQueue.put(() => {
+               console.log('microTask1');
+               microTaskQueue.put(() => {
+                   console.log('microTask2');
+               });
+           });
        });
    });
    browser.send({ type: 'click', data: 'clicked' });
})();
browser.js
//浏览器主进程
process.on('message', function ({ data }) {
    setTimeout(() => {
        process.send({ data });
    }, 100);
});
messageQueue.js
class MessageQueue {
    constructor() {
        this.messages = [];
    }
    put(message) {
        this.messages.push(message);
    }
    get() {
        return this.messages.pop();
    }
}
+exports.macroTaskQueue = new MessageQueue();
+exports.microTaskQueue = new MessageQueue();
DelayTask.js
let timerCounter = 1;
class DelayTask {
    constructor(callback, delayTime) {
        this.id = timerCounter++;
        this.startTime = Date.now();
        this.callback = callback;
        this.delayTime = delayTime;
    }
}
module.exports = DelayTask;
render.js
const { fork } = require('child_process');
const { macroTaskQueue, microTaskQueue } = require('./messageQueue');
+const DelayTask = require('./DelayTask');
+let delayTaskQueue = [];
(function mainThread() {
    setInterval(() => {
        let macroTask = macroTaskQueue.get();
        if (macroTask) macroTask();
+       processDelayTask();
        let microTask;
        while (microTask = microTaskQueue.get()) {
            microTask();
        }
    }, 16);
})();
+function setTimeout(callback, delayTime) {
+    delayTaskQueue.push(new DelayTask(callback, delayTime));
+}
+function clearTimeout(timeId) {
+    delayTaskQueue = delayTaskQueue.filter(delayTask => {
+        return delayTask.id !== timeId;
+    });
+}
+function processDelayTask() {
+    delayTaskQueue = delayTaskQueue.filter(delayTask => {
+        const { callback, startTime, delayTime } = delayTask;
+        if (Date.now() > startTime + delayTime) {
+            macroTaskQueue.put(callback);
+            return false;
+        }
+        return true;
+    });
+}
(function IOThread() {
    let browser = fork('./browser.js');
+   console.time('cost');
    browser.on('message', function ({ data }) {
        console.log(data);
+        setTimeout(() => {
+            console.timeEnd('cost');
+        }, 1000);
    });
    browser.send({ type: 'click', data: 'clicked' });
})();
XMLHttpRequest是由浏览器进程或发起请求,然后再将执行结果利用 IPC 的方式通知渲染进程,之后渲染进程再将对应的消息添加到消息队列中
render.js
const { fork } = require('child_process');
const { macroTaskQueue, microTaskQueue } = require('./messageQueue');
(function mainThread() {
    setInterval(() => {
        let macroTask = macroTaskQueue.get();
        if (macroTask) macroTask();
        let microTask;
        while (microTask = microTaskQueue.get()) {
            microTask();
        }
    }, 16);
})();
(function IOThread() {
    let browser = fork('./browser.js');
    console.time('cost');
    browser.on('message', function () {
+       let xhr = new XMLHttpRequest();
+       xhr.open('GET', 'http://localhost:3000/data');
+       xhr.onload = function () {
+           console.log(xhr.response);
+       }
+       xhr.send();
    });
    browser.send({ type: 'click', data: 'clicked' });
})();
+class XMLHttpRequest {
+    constructor() {
+        this.options = {};
+    }
+    open(method, url) {
+        this.options.method = method;
+        this.options.url = url;
+    }
+    send() {
+        let child = fork('./XMLHttpRequest.js');
+        child.on('message', (message) => {
+            if (message.type === 'response') {
+                this.response = message.data;
+                macroTaskQueue.put(this.onload);
+            }
+        });
+        child.send({ type: 'send', options: this.options });
+    }
+}
XMLHttpRequest.js
let url = require('url');
let http = require('http');
process.on('message', function (message) {
    let { type, options } = message;
    if (type == 'send') {
        let urlObj = url.parse(options.url);
        const config = {
            hostname: urlObj.hostname,
            port: urlObj.port,
            path: urlObj.path,
            method: options.method
        };
        var req = http.request(config, (res) => {
            let chunks = [];
            res.on('data', (chunk) => {
                chunks.push(chunk);
            });
            res.on('end', () => {
                process.send({
                    type: 'response',
                    data: JSON.parse(Buffer.concat(chunks).toString())
                });
                process.exit();
            });
        });
        req.on('error', (err) => {
            console.error(err);
        });
        req.end();
    }
});
server.js
var http = require("http");
var server = http.createServer();
server.on("request", function (request, response) {
    response.end(JSON.stringify({ message: 'hello' }));
})
server.listen(3000, function () {
    console.log("服务已经在3000端口启动!")
});

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="tree"></div>
    <button onclick="start()">开始监听</button>
    <button onclick="changeAttribute()">修改属性</button>
    <button onclick="addChild()">添加子节点,3秒后删除</button>
    <script>
        var targetNode = document.getElementById('tree');
        var config = { attributes: true, childList: true, subtree: true };
        var callback = function (mutationsList) {
            for (var mutation of mutationsList) {
                console.log(mutation);
                if (mutation.type == 'childList') {
                    console.log('添加或删除子节点');
                    console.log(mutation.addedNodes);
                    console.log(mutation.removedNodes);
                } else if (mutation.type == 'attributes') {
                    console.log('属性 ' + mutation.attributeName + ' 被改变了');
                }
            }
        };
        var observer = new MutationObserver(callback);
        function start() {
            observer.observe(targetNode, config);
        }
        function changeAttribute() {
            targetNode.setAttribute('data-name', '树');
        }
        function addChild() {
            let child = document.createElement('div');
            child.innerHTML = '子节点';
            targetNode.appendChild(child);
            setTimeout(() => {
                targetNode.removeChild(child);
            }, 2000);
        }
    </script>
</body>
</html>



setTimeout(function  () {
  console.log('timeout');
},0);
setImmediate(function  () {
  console.log('immediate');
});
const fs = require('fs')
fs.readFile(__filename, () => {
    setTimeout(() => {
        console.log('timeout');
    }, 0)
    setImmediate(() => {
        console.log('immediate')
    })
})
setTimeout(() => {
    console.log('setTimeout1')
    Promise.resolve().then(function () {
        console.log('promise1')
    })
}, 0)
setTimeout(() => {
    console.log('setTimeout2')
    Promise.resolve().then(function () {
        console.log('promise2')
    })
}, 0)
setImmediate(() => {
    console.log('setImmediate1')
    Promise.resolve().then(function () {
        console.log('promise3')
    })
}, 0)
process.nextTick(() => {
    console.log('nextTick1');
    Promise.resolve().then(() => console.log('promise4'));
    process.nextTick(() => {
        console.log('nextTick2');
        Promise.resolve().then(() => console.log('promise5'));
        process.nextTick(() => {
            console.log('nextTick3')
            process.nextTick(() => {
                console.log('nextTick4')
            })
        })
    })
})
// nextTick1 nextTick2 nextTick3 nextTick4
//promise4 promise5 setTimeout1  promise1 setTimeout2 promise2  setImmediate1 promise3 
let fs = require('fs');
setTimeout(() => {
    console.log('1');
    let rs1 = fs.createReadStream(__filename);
    rs1.on('data', () => {
        rs1.destroy();
        setImmediate(() => console.log('setImmediate_a'));
        setTimeout(() => {
            console.log('setTimeout_a')
        });
        console.log('a');
    });
    rs1.on('close', () => console.log('end_a'));
    console.log('2');
    setImmediate(function () {
        console.log('setImmediate1');
        process.nextTick(() => console.log('nextTick1'));
    });
    setImmediate(function () {
        console.log('setImmediate2');
        process.nextTick(() => console.log('nextTick2'));
    });
    console.log('3');
    setTimeout(() => {
        console.log('setTimeout1');
        process.nextTick(() => {
            console.log('nextTick3')
            process.nextTick(() => console.log('nextTick4'));
        });
    });
    setTimeout(() => {
        console.log('setTimeout2');
    });
    console.log('4');
}, 1000);
const Promise = require('./Promise');
Promise.resolve().then(() => {
    console.log(0);
    return new Promise((resolve)=>{
        resolve('a');
    })
}).then(res => {
    console.log(res)
})
Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(4);
}).then(() => {
    console.log(5);
})
// 0 1 2 3 a 4 5
const Promise = require('./Promise');
let promise1 = Promise.resolve();
let promise2 = promise1.then(() => {
    console.log(0);
    let promise10 = Promise.resolve('a');
    return promise10;
})
let promise3 = promise2.then(res => {
    console.log(res)
})
let promise4 = Promise.resolve();
let promise5 = promise4.then(() => {
    console.log(1);
});
let promise6 = promise5.then(() => {
    console.log(2);
});
let promise7 = promise6.then(() => {
    console.log(3);
});
let promise8 = promise7.then(() => {
    console.log(4);
});
let promise9 = promise8.then(() => {
    console.log(5);
})
// 0 1 2 3 a 4 5
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
function resolvePromise(promise, x, resolve) {
    if (x && typeof x.then === 'function') {
        queueMicrotask(() => {
            console.log('resolvePromise: microtask', x.id);
            x.then(y => resolvePromise(promise, y, resolve));
        });
    } else {
        resolve(x)
    }
}
class Promise {
    static counter = 1;
    constructor(executor) {
        this.id = Promise.counter++;
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        const resolve = (value) => {
            if (value instanceof Promise) {
                return queueMicrotask(() => {
                    console.log('resolve: microtask', value.id);
                    value.then(resolve)
                });
            }
            if (this.status == PENDING) {
                this.value = value;
                this.status = FULFILLED
                this.onResolvedCallbacks.forEach(cb => cb(this.value))
            }
        }
        executor(resolve);
    }
    then(onFulfilled) {
        let newPromise = new Promise((resolve) => {
            if (this.status === FULFILLED) {
                queueMicrotask(() => {
                    console.log('FULFILLED then: microtask', this.id);
                    let x = onFulfilled(this.value);
                    resolvePromise(newPromise, x, resolve)
                })
            }
            if (this.status == PENDING) {
                this.onResolvedCallbacks.push(() => {
                    queueMicrotask(() => {
                        console.log('PENDING then: microtask', this.id);
                        let x = onFulfilled(this.value);
                        resolvePromise(newPromise, x, resolve)
                    })
                });
            }
        });
        return newPromise;
    }
    static resolve(value) {
        return new Promise((resolve) => {
            resolve(value)
        })
    }
}
module.exports = Promise;
console.log('FULFILLED then: microtask', this.id);
let x = onFulfilled(this.value);//x=k
resolvePromise(p1, x, resolve, reject)
然后继续调用promise2的then方法,发现promise2还处于等待态,不能直接添加微任务,只能添加
() => {
  queueMicrotask(() => {
      console.log('PENDING then: microtask', this.id);
      let x = onFulfilled(this.value);
      resolvePromise(p1, x, resolve)
  })
}
到promise2的onResolvedCallbacks的尾部,并返回promise3,这个promise3后面没有再用到了,此时第一段代码结束
开始执行第二段代码
queueMicrotask(() => {
  console.log('FULFILLED then: microtask',4);
  let x = onFulfilled(this.value);//x=k
  resolvePromise(newPromise, x, resolve)
})
this.onResolvedCallbacks.push(() => {
 queueMicrotask(() => {
     console.log('PENDING then: microtask', this.id);
     let x = onFulfilled(this.value);//  console.log(2);
     resolvePromise(newPromise, x, resolve)
 })
});
this.onResolvedCallbacks.push(() => {
 queueMicrotask(() => {
     console.log('PENDING then: microtask', this.id);
     let x = onFulfilled(this.value);//  console.log(3);
     resolvePromise(newPromise, x, resolve)
 })
});
this.onResolvedCallbacks.push(() => {
 queueMicrotask(() => {
     console.log('PENDING then: microtask', this.id);
     let x = onFulfilled(this.value);//  console.log(4);
     resolvePromise(newPromise, x, resolve)
 })
});
this.onResolvedCallbacks.push(() => {
 queueMicrotask(() => {
     console.log('PENDING then: microtask', this.id);
     let x = onFulfilled(this.value);//  console.log(5);
     resolvePromise(newPromise, x, resolve)
 })
});
然后继续调用promise9的then方法,发现promise9还处于等待态,不能直接添加微任务,只能添加
this.onResolvedCallbacks.push(() => {
 queueMicrotask(() => {
     console.log('PENDING then: microtask', this.id);
     let x = onFulfilled(this.value);//  console.log(6);
     resolvePromise(newPromise, x, resolve)
 })
});
此时,任务列队上有两个新任务
微任务队列 [FULFILLED then: microtask 1,FULFILLED then: microtask 4]
FULFILLED then: microtask 1 执行resolvePromise(promise2, promise10, resolve)的时候,如果发现promise10是一个promise,并且入队console.log('resolvePromise: microtask 10');
x.then(y => resolvePromise(promise, y, resolve));
FULFILLED then: microtask 4,resolvePromise: microtask 10]FULFILLED then: microtask 4,输出1PENDING then: microtask 5入队,此时本任务结束resolvePromise: microtask 10,PENDING then: microtask 5]resolvePromise: microtask 10,因为promise10是直接成功的,直接执行成功回调,入队console.log('FULFILLED then: microtask 10');
let x = onFulfilled(this.value);
resolvePromise(newPromise, x, resolve)
PENDING then: microtask 5,FULFILLED then: microtask 10]PENDING then: microtask 5,输出2PENDING then: microtask 6入队,此时本任务结束FULFILLED then: microtask 10,PENDING then: microtask 6]FULFILLED then: microtask 10,它会让promise2变成成功态,并且把promise2的成功回调入队PENDING then: microtask 6,FULFILLED then: microtask 2]PENDING then: microtask 6,输出3,PENDING then: microtask 7入队,此时本任务结束FULFILLED then: microtask 2,PENDING then: microtask 7]FULFILLED then: microtask 2,输出aPENDING then: microtask 7,输出4PENDING then: microtask 8入队,此时本任务结束PENDING then: microtask 8]PENDING then: microtask 8,输出5FULFILLED then: microtask 1
0
FULFILLED then: microtask 4
1
resolvePromise: microtask 10
PENDING then: microtask 5
2
FULFILLED then: microtask 10
PENDING then: microtask 6
3
PENDING then: microtask 2
a
PENDING then: microtask 7
4
PENDING then: microtask 8
5
const Promise = require('./Promise');
Promise.resolve().then(() => {
    console.log(0);
    return new Promise((resolve) => {
        resolve(new Promise((resolve) => {
            resolve('a');
        }));
    })
}).then(res => {
    console.log(res)
})
Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(4);
}).then(() => {
    console.log(5);
})
// 0 1 2 3  4 a 5