课程名称: 破解JavaScript高级玩法
课程章节: 爱上异步编程
主讲老师: Cloud
今天学习的内容包括:
现代异步编程的核心:Promise
回调函数:
function login(callback) { setTimeout(() => { callback("token"); }, 3000); } function getOrderId(token,callback) { if(token){ setTimeout(() => { callback("orderId"); }, 2000); } } function orderDetails(orderId,callback) { if(orderId){ setTimeout(() => { callback("淘宝订单:购买xxx书一本"); }, 1500); } } login((token) => { getOrderId(token,(orderId) => { orderDetails(orderId,(orderInfo) => { console.log(orderInfo); }); }); });
回调函数异常:
function login(callback) { setTimeout(() => { callback("token"); }, 2); } function getOrderId(token,callback) { if(token){ setTimeout(() => { callback("orderId"); }, 3); } } function orderDetails(orderId,callback) { if(orderId){ setTimeout(() => { callback("淘宝订单:购买xxx书一本"); }, 2); } } try{ login((token) => { throw new Error("orderList"); getOrderId(token,(orderId) => { orderDetails(orderId,(orderInfo) => { console.log(orderInfo); }); }); }); }catch(e){ console.log("try catch error:",e); }
简版延迟函数:
/** * * * @param {any} fn 需要延迟的方法 * @param {any} delay 延迟时间 * @param {any} context 上下文 * @returns */ function delay(fn, delay, context) { let defaultDelay = delay || 5000; let ticket; return { run(...args) { ticket = setTimeout(async () => { fn.apply(context, args); }, defaultDelay) }, cancel: () => { clearTimeout(ticket); } } } const { run, cancel } = delay(() => { console.log("111") }, 3000); run(); setTimeout(() => { cancel(); }, 1000);
延迟函数:
function isFunction(fn) { return typeof fn === 'function' || fn instanceof Function } /** * * * @param {any} fn 需要延迟的方法 * @param {any} delay 延迟时间 * @param {any} context 上下文 * @returns */ function delay(fn, delay, context) { let defaultDelay = delay || 5000; if (!isFunction(fn)) { return { run: () => Promise.resolve(), cancel: noop } } let ticket; let executed = false; return { run(...args) { return new Promise((resolve, reject) => { if (executed === true) { return; } executed = true; ticket = setTimeout(async () => { try { const res = await fn.apply(context, args); resolve(res); } catch (err) { reject(err) } finally { clearTimeout(ticket); } }, defaultDelay) }) }, cancel: () => { clearTimeout(ticket); } } } //测试 const { run, cancel } = delay(() => { return "函数执行结果" }, 3000); run().then((result) => { console.log("result:", result); }) run().then(() => { console.log("多次调用run result:", result); });
重试多次:
function isFunction(fn) { return typeof fn === 'function' || fn instanceof Function } function retry(fun, count, assert = () => false) { if (!isFunction(fun)) { return Promise.resolve(); } return new Promise(async (resolve, reject) => { let error = null; //错误值 for (let tryCount = 1; tryCount <= count; tryCount++) { try { const value = await fun(tryCount); if (assert(value, tryCount)) { return resolve(value); } } catch (e) { error = e; } } reject(new Error("多次尝试失败")) }); } // retry(()=>{ // throw new Error("错误") // },3).catch((e)=>{ // console.log("捕获到错误:",e) // }); let index = 0; function createPromise(tryCount) { console.log("尝试次数:", tryCount) return new Promise((resolve, reject) => { index++; setTimeout(() => { resolve(index) }, 1000) }) } retry(createPromise, 10, (res) => { return res == 5 }).then((res) => { console.log("当前的数据:", res); }).catch((e) => { console.log("捕获到错误:", e) });
EventEmitter:
import { BaseAsyncMessager, BaseReqData, GlobalReqOptions } from "../src/index"; import EventEmitter from "events"; const emitter = new EventEmitter(); interface RequestData extends BaseReqData { method: string; data?: any; } type ResponseData = RequestData; // 初始化异步Messager const emitterAsyncMessager = new BaseAsyncMessager<RequestData>({ subscribe(onMessage) { console.log("emitterAsyncMessager: subscribe"); emitter.on("message", onMessage as any); return () => { emitter.off("message", onMessage as any); } }, getReqCategory(data: RequestData) { console.log("emitterAsyncMessager: getReqCategory: method", data.method); return data.method; }, getResCategory(data: ResponseData) { return data.method; }, request(data: RequestData, key?: string) { emitter.emit("message-request", data); } }); /* 模拟emitter另外一端 */ // 传统的事件通知 setInterval(() => { emitter.emit('message', { method: 'continuous-event', data: new Date().toLocaleTimeString() }) }, 3000) // 监听 message-request 事件,然后回发事件 emitter.on("message-request", (data: RequestData) => { setTimeout(() => { emitter.emit("message", { method: data.method, data: `${data.method}--- data` }) }, 3000) }) /*使用方 */ // 调用 emitterAsyncMessager.invoke({ method: "cccc", data: 111 }).then(res => console.log("res:", res)) // 传统的监听事件 emitterAsyncMessager.addHandler("continuous-event", function onEvent(data) { console.log("continuous-event:", data); })
iframe:
<iframe class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="./iframe1.html" id="ifr"></iframe> <script class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="../../dist/asyncMessager.js"></script> <script> function sendMessage(msg) { iframe1.contentWindow.postMessage(msg) } const iframe1 = document.getElementById("ifr"); const asyncMessager = new AsyncMessager.BaseAsyncMessager({ // logUnhandledEvent: false, subscribe(onMessage) { function onIframeMessage(msg) { onMessage(msg.data); } window.addEventListener("message", onIframeMessage); return () => { window.removeEventListener("message", onIframeMessage); } }, getReqCategory(data) { console.log("asyncMessager getReqCategory: method", data.method); return data.method; }, getResCategory(data) { return data.method; }, request(data, key) { sendMessage(data); } }); iframe1.contentWindow.onload = () => { asyncMessager.invoke({ method: "init", data: { user: 123456, token: "blabla......" } }).then(res => console.log("index.html:", res, res)) } asyncMessager.addHandler("timeInfo", function(data){ console.log("index.html:timeInfo", data); }) </script>
socket.io:
const socket = io("http://localhost:3000"); function sendMessage(msg) { socket.emit("message", msg) } const asyncMessager = new AsyncMessager.BaseAsyncMessager({ // logUnhandledEvent: false, subscribe(onMessage) { function onSocketMessage(msg) { onMessage(msg); } socket.on("message", onSocketMessage); return () => { socket.off("message", onSocketMessage); } }, request(data, key) { sendMessage(data); } }); socket.on("connect", () => { console.log("connect") asyncMessager.invoke({ method: "getUsers", data: { user: 123456, token: "blabla......" } }).then(res => console.log("index.html:", res, res)) }); asyncMessager.addHandler("timeInfo", function (data) { console.log("index.html:timeInfo", data); });