Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器在同js文件下执行后台线程Worker #35

Open
chenshenhai opened this issue Jun 24, 2019 · 0 comments
Open

浏览器在同js文件下执行后台线程Worker #35

chenshenhai opened this issue Jun 24, 2019 · 0 comments
Labels

Comments

@chenshenhai
Copy link
Owner

chenshenhai commented Jun 24, 2019

前言

对于js的Worker的使用,看了很多网上资料,都是基于worker.js新开一个文件来执行后台线程。

但是如果不想太麻烦新开一个work.js文件,想在同一个js文件里执行后台线程的资料就很少,最后翻遍了MDN 文档,找到了一种在同js文件下执行后台线程Worker的方法,具体实现如下

实现

实现源码

/**
 * 执行函数的后台线程
 * @param func 待后台线程执行的函数
 * @param params 待后台线程执行的函数参数
 * @param feedback 执行后台线程函数后反馈回调函数
 */
 const asyncWorker = function (func, params, feedback) {
   // 设置后台执行函数的UUID
  const uuid = Math.random().toString(26).substr(2);

  // 封装成自执行函数字符串
  const scriptCode = `(${func.toString()})(event.data.params)`;
  const feedbackMap = new Map();
  // 后台线程代码字符串
  const workerCode = `
    onmessage = function (event) {
      let result = null;
      let err = null;
      result = eval(event.data.code);
      postMessage({
        id: event.data.id,
        result: result,
        error: err,
      });
    }
  `;
  const workerCodeStr = encodeURIComponent(workerCode);
  // 初始化后台线程
  const worker = new Worker('data:text/javascript;charset=US-ASCII,' + workerCodeStr);

  // 监听正常后台线程通信
  worker.onmessage = function (event) {
    const callback = feedbackMap.get(event.data.id);
    if (typeof callback === 'function') {
      callback(event.data.result, event.data.error);
    }
    feedbackMap.delete(event.data.id);
  };

  // 捕获后台线程错误
  worker.onerror = function (err) {
    const callback = feedbackMap.get(uuid);
    if (typeof callback === 'function') {
      callback(null, err.message);
    }
    feedbackMap.delete(uuid);
  };

  // 将函数存入map中
  feedbackMap.set(uuid, feedback);

  // 发起通信,执行ID为UUID的函数
  worker.postMessage({
    id: uuid,
    params: params,
    code: scriptCode
  });
};

执行正常后台线程

// 待执行在后台线程函数
// 斐波那契数列函数
const fibonacciFunc = function(params = {}) {
  const { count = 1 } = params;
  let result = 1;
  for (let i = 0; i < count; i ++) {
    result += result;
  }
  return result;
}
// 斐波那契数列的参数为 50
const params = { count: 50 };
// 开始执行后台线程 计算数列
asyncWorker(fibonacciFunc, params, function (result, err) {
  console.log('result = ', result);
  console.log('error = ', err);
});
执行结果
# 斐波那契数列 执行结果
result =  1125899906842624
error =  null

执行异常后台线程

// 待执行在后台线程 异常函数
const errorFunc = function(params = {}) {
  throw new Error('i am an error')
}
// 开始执行后台线程 异常函数
asyncWorker(errorFunc, {}, function (result, err) {
  console.log('result = ', result);
  console.log('error = ', err);
});
执行结果
result =  null
error =  Uncaught Error: i am an error

参考

MDN:Web/API/Web_Workers_API/Using_web_workers

@chenshenhai chenshenhai changed the title 在浏览器里同js文件下执行后台线程Worker 浏览器在同js文件下执行后台线程Worker Jun 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant