异步
异步和 同步的概念,这边就不去做 阐述了。 无非js的 执行时 单线程的,所以 js的 虚拟机在 执行上 维护这两个 队列,我们 熟知的 宏队列 和 微队列。 宏队列有
setTimeout,setInterval等, 微任务有Promise的 callback(then, catch),queueMicrotask. 二者 交替顺序就是 先宏任务 =》 微任务 =》 宏任务。。。 下面就简单 过一下 执行顺序, log 的就是执行顺序
// 注册宏任务
setTimeout(() => {
console.log(6)
})
console.log(1)
// 注册微任务
Promise.resolve().then(() => {
console.log(3)
})
new Promise(r => {
// 本质上是 同步的
console.log(2)
r()
}).then(() => {
console.log(4)
// 这里注意一下,这里注册了就会马上执行
Promise.resolve().then(() => {
console.log(5)
})
})
但是 => WebWorker
在我们 有大量运算计时 或者 请求耗时上,往往是 用异步的 形式去做处理,比如用 Promise 包一层, 或者直接 Promise.resolve() 去让计算 放到微任务中,防止阻止UI的 绘制。 但是本质上 依旧 是当前线程 去做。 例如 在 前一个微任务的执行就是 阻塞 影响下一个 微任务执行-。-
所以这个时候 就只能 新开一个 线程 去做 WebWorker。 具体介绍就看 MDN
具体用法就是 new Worker 来开辟新 线程进行处理。 但是 该构造函数 只支持 URL, 但是看了 MDN 也是支持 BlobUrl 的,所以,就可以这样写。
// 使用 URL.createObjectURL 去创建 blob url, url返回的就是 我们js 代码
URL.createObjectURL(new Blob(['console.log(123)']))
使用 URL.createObjectURL 去创建 blob url, url返回的就是 我们js 代码
所以思路就很清楚了
const runInAsync = fn => {
return new Promise((res, rej) => {
// 判断是否支持 WebWorker 不支持就乖乖用 Promise 异步去做吧
if (typeof Worker === 'undefined') {
Promise.resolve().then(() => {
res(fn())
})
} else {
// 这个 Worker 就是 postMessage 回来真正的 执行
const worker = new Worker(
URL.createObjectURL(new Blob([`postMessage((${fn})())`]))
)
worker.onmessage = ({data}) => {
res(data)
worker.terminate()
}
worker.onerror = err => {
rej(err)
worker.terminate()
}
}
})
}
以上的
runInAsync就是 真的的异步 执行,是会优先开辟线程 Worker去做的。不会影响到 别的任务执行
测试
我们先写一个 复杂 运算的 function -。-
// 用三个 for 去做循环
const longRunningFunction = () => {
let result = 0;
for (let i = 0; i < 1000; i++)
for (let j = 0; j < 700; j++)
for (let k = 0; k < 1000; k++) result = result + i + j + k;
console.log(result)
return result;
};
然后去执行 如下,所以,本质上 还是会阻塞掉 我们的 第二个微任务
Promise.resolve().then(() => {
longRunningFunction()
})
Promise.resolve().then(() => {
console.log('micro done')
})
console.log('done')
使用 runInAsync。 因为本质上是 用了另一个线程去做,所以,当然不会阻塞啦
runInAsync(longRunningFunction).then(data => {
console.log('longRunningFunction invoke data:', data)
})
Promise.resolve().then(() => {
console.log('micro done')
})
console.log('done')
结语
本质 上 东西很简单, 是WebWorker 的一个简单应用, 无非使用了 BlobUrl 的一种形式去 包裹一层我们的真正执行代码,来巧妙的 去使用 WebWorker。 算了 开阔了一种思路吧。 So. Just have a Good Day!