<!doctype html> <html lang="zh"> <head> <meta charset="utf-8"> <title>Worker多线程具体使用示例</title> </head> <body> <script type="text/javascript"> let worker = new Worker('worker.js'); worker.onerror = function (event) { console.log('子线程[worker.js]出错辣~~~', event); }; // 接收worker子线程消息 worker.onmessage = function (event) { let data = event.data; // 获取消息内容 //========== 处理子线程消息:哈希运算 ==========// if (data.action === 'hash') { console.log('md5(\'%s\') ===> ', data.str, data.md5); console.log('sha512(\'%s\') ===> ', data.str, data.sha512); // md5('Worker') ===> 62efb9ec331e364b96efe68c8b03ca20 // sha512('Worker') ===> 772053c8c3ea79e68515dab11bf9950cfdbe163ccc5bc08acafd2b91eef04bccffcfbac7abd04ea480d218…… return; } //========== 处理子线程消息:AJAX请求 ==========// if (data.action === 'ajax') { let response = data.response; if (response.errcode === 0) { let name = response.name; let gender = response.gender; let age = response.age; console.log('俺叫%s(%s),今年%d岁。', name, gender, age); // 俺叫张三(男),今年18岁。 } else { alert(response.errmsg); } return; } //========== 处理子线程消息:其它 ==========// // TODO... }; // 向worker子线程发送消息(哈希运算) worker.postMessage({action: 'hash', str: 'Worker'}); // 可直接将对象作为参数,不需要转为字符串(下同) // 向worker子线程发送消息(AJAX请求) worker.postMessage({ action: 'ajax', // 设置AJAX请求的option,这里仿照jQuery的$.ajax({...})写法 options: { url: './ajax.php', method: 'POST', responseType: 'json', data: {uid: 9527}, async: true, timeout: 1000 * 30, // beforeSend: function (xhr) { // 重要提醒:消息不能传递function类型,否则会报“could not be cloned”错误,也就是 // console.log(xhr); 说想在子线程里执行beforeSend、success等回调操作是行不通的,只能老老实 // }, 实让子线程把响应结果发回给主线程,由主线程来处理响应结果。 // success: function (response) { // console.log(response); // }, } }); // 销毁worker子线程 // worker.terminate(); </script> </body> </html>
//========== worker.js ==========// // 在子线程里也可以加载其它JavaScript文件,且可以一次加载多个文件 importScripts('function.lib.js', 'util.js'); // 接收主线程消息 self.onmessage = function (event) { let data = event.data; // 获取消息内容 // 向主线程发送消息(延迟执行模拟耗时操作) setTimeout(function () { //========== 处理主线程消息:哈希运算 ==========// if (data.action === 'hash') { let message = {}; message.action = data.action; message.str = data.str; message.md5 = md5(data.str); message.sha512 = sha512(data.str); self.postMessage(message); return; } //========== 处理主线程消息:AJAX请求 ==========// if (data.action === 'ajax') { let xhr = new XMLHttpRequest(); // 创建XMLHttpRequest对象 let options = data.options; // AJAX请求的option // 服务器响应内容类型,可选值:'' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' xhr.responseType = options.responseType; // 请求超时时间,单位:毫秒 xhr.timeout = options.timeout; // 请求完成后的回调函数(注意:请求完成不是请求成功,也可能是请求失败或请求超时) xhr.onreadystatechange = function () { let message = {}; message.action = data.action; // 设置通用错误响应,后续会根据状态码进一步判断是什么错误 message.response = {errcode: 1, errmsg: '请求失败'}; if (xhr.readyState === XMLHttpRequest.DONE) { // 根据状态码判断是什么错误 switch (xhr.status) { case 0: { message.response.errmsg = '请求超时'; break; } case 200: { message.response = xhr.response; // 请求成功,将响应结果原样附加进消息然后发回给主线程即可 break; } case 404: { message.response.errmsg = '404 Not Found'; break; } case 500: { message.response.errmsg = '500 Internal Server Error'; break; } default: { message.response.errmsg = '请求失败(' + xhr.status + ')'; } } self.postMessage(message); } }; // 创建请求(注意:此时还未发起请求) xhr.open( options.method, // 请求方法,可选值:GET|POST|PUT|DELETE options.url, // 请求URL options.async // 是否异步 ); // 设置POST参数 let formData = new FormData(); Object.entries(options.data).forEach(function ([key, value]) { formData.append(key, value); }); // 带上POST参数发起请求 xhr.send(formData); return; } //========== 处理主线程消息:其它 ==========// // TODO... }, 3000); };
//========== function.lib.js ==========// /** * 计算字符串的md5散列值 * * @param str string 字符串 * @return string 字符串的md5散列值 */ function md5(str) { // 由于本文核心是演示如何使用Worker多线程,这里就不具体实现md5逻辑,直接返回一串字符串 return '62efb9ec331e364b96efe68c8b03ca20'; } /** * 计算字符串的sha512散列值 * * @param str string 字符串 * @return string 字符串的sha512散列值 */ function sha512(str) { // 由于本文核心是演示如何使用Worker多线程,这里就不具体实现sha512逻辑,直接返回一串字符串 let hash = ''; hash += '772053c8c3ea79e68515dab11bf9950cfdbe163ccc5bc08acafd2b91eef04bcc'; hash += 'ffcfbac7abd04ea480d218382ee404b30380a3871d1004c7bc2fbb067a1efb5a'; return hash; }
//========== util.js ==========// // TODO...
<?php //========== ajax.php ==========// if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 这里模拟根据UID获取用户信息 $return = ['errcode' => 1, 'errmsg' => '用户不存在']; $uid = isset($_POST['uid']) ? (int)$_POST['uid'] : 0; if ($uid === 9527) { $return['errcode'] = 0; $return['errmsg'] = ''; $return['name'] = '张三'; $return['gender'] = '男'; $return['age'] = 18; } try { header('Content-Type:application/json; charset=utf-8'); echo json_encode($return, JSON_THROW_ON_ERROR | 320); } catch (JsonException $e) { header('Content-Type:text/html; charset=utf-8'); echo 'JsonException: ' . $e->getMessage(); } }
//========== 由主线程执行的代码 ==========// if (typeof window !== 'undefined') { // 获取当前JavaScript脚本URL,并创建子线程执行当前JavaScript脚本里的子线程代码 let scriptURL = document.scripts[document.scripts.length - 1].src; let worker = new Worker(scriptURL); worker.onerror = function (event) { console.log('子线程出错辣~~~', event); }; // 接收子线程消息 worker.onmessage = function (event) { console.log('主线程收到子线程消息:' + event.data); }; // 向子线程发送消息 worker.postMessage('PHP'); // 销毁子线程 // worker.terminate(); } //========== 由子线程执行的代码 ==========// if (typeof window === 'undefined') { // 接收主线程消息 self.onmessage = function (event) { console.log('子线程收到主线程消息:' + event.data); // 向主线程发送消息(延迟执行模拟耗时操作) setTimeout(function () { self.postMessage(event.data + '·从入门到放弃'); // 向主线程发送消息 self.close(); // 关闭子线程 }, 2500); }; } //========== 控制台输出结果·开始 ==========// // 子线程收到主线程消息:PHP // 主线程收到子线程消息:PHP·从入门到放弃 //========== 控制台输出结果·结束 ==========//
Copyright © 2024 码农人生. All Rights Reserved