一、js多线程
1.ConcurrentThread
在webworker之前,js只有单线程,但是有一些方法可以模拟多线程。
一个日本人开发的库 ConcurrentThread.js,他模拟多线程的原理是:
假设我有一个while循环,把它扔到 Concurrent 方法的回调函数中,他把你的回调函数取函数体,然后对函数体进行类似 AST 分析,然后把while循环替换成 requestAnimationFrame 之类的异步方法。
它的另一种做法是在 <script type="text/x-script.multithreaded-js"> 内写代码,实际上道理类似,对标签内部做 AST 分析。
2.webworker
webworker能够开辟一个新的对象,不占用window对象,所以它有自己的一个线程。所以死循环也不会造成页面阻塞。
⚠️webworker需要服务启动页面。
在html中:
// index.js是业务js
const worker = new Worker('./index.js');
worker.onmessage = function ({ data }){
// 获得返回的值
console.log(data);
// 关闭这个worker
self.close();
};
// 通知 message 开始
worker.postMessage('worker post-message start');
在业务js中:
onmessage = function (){
// 开始
let i = 0;
// 处理一个非常占用线程的同步任务
for (; i < 1000000000; i++) {}
// 通知worker对象同步任务已经完成
postMessage(i);
};
在上述代码中,业务js的for循环不会造成主线程阻塞。
二、协程
对操作系统来说,线程是最小的执行单元,进程是最小的资源管理单元。
协程是比线程更轻量级的概念,
一个进程可以有多个线程;一个线程可以有多个协程。
协程可以锁线程,在执行到当前代码前,当前代码 到 上一个协程结束后的代码 的 中间的代码 不执行。
1.promise
new Promise(resolve => {
// 同步
console.log(1);
resolve();
new Promise(__resolve => {
// 同步
console.log(2);
__resolve();
})
.then(() => {
// 异步1, ⚠️内部的then先执行
console.log(4);
});
})
.then(() => {
// 异步2
console.log(5);
});
// 同步
console.log(3);
2.generator
let a = 0;
// generator函数
function * generator(){
a++;
// ⚠️协程,锁变量,直到再次执行之前不会变
yield a++;
a++;
yield a++;
}
const g = generator();
// 0 虽然调用了 generator ,但在调用 next 前,函数不会执行
console.log(a);
a++;
// 1
console.log(a);
g.next();
// 3
console.log(a);
a++;
// 4
console.log(a);
g.next();
// 6
console.log(a);
3.async
async 是 generator函数function *(){}的语法糖。
async 代码:await只是阻塞了当前表达式本身,但是作为表达式的元素,如果是一个表达式,还是要先执行完。
let a = 0;
let f = async function (){
// 没有遇到await,同步执行,此时 a === 1
a++;
// 执行所有与await无关的表达式
// (a++) 与 (a = a + 1) 是await所在表达式的元素,先得得到这两个表达式的值
// (a++) 后 a === 2,(a++) 表达式的值为1
// (a = a + 1) 后 a === 3,表达式的值为3
// 此时返回主线程
// 。。。。主线程完成后。。。。
// 执行await,表达式的元素分别被锁定,a = 1 + 3 + 10
a = a++ + await (a = a + 1) + 10;
// 故 a === 14
console.log(a === 14);
};
// 执行函数
f();
// 主线程,返回到此时,a === 3
console.log(a === 3);
a++;
// a === 4
console.log(a === 4);
// 主线程执行完,返回携程
const f1 = async () => {
// 同步
console.log(1);
// 同步执行f2
// 执行完f2后,返回主线程
// .........
// 主线程完成后,先进入f2的携程,因为f2作为f1中await的操作元,还没有执行完 ⚠️ ->
await f2();
// ->💡
console.log(5);
};
const f2 = async () => {
// 同步
console.log(2);
// 返回主线程,对于f2来说,主线程是f1
await null;
// ->⚠️
console.log(4);
// 💡->
};
// 开始
f1();
// 同步,主线程完成,返回携程
console.log(3);