一、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);