# 异步编程
# 同步和异步的概念
# 同步
执行某个任务时,没有得到结果前,不会执行后续的操作。
# 异步
一个异步任务执行后,没有得到结果之前,就可以继续执行后续操作。异步任务完成后,一般通过回调通知调用者。例如setTimeout,fetch/XMLHttpRequest等。
# 使用回调函数
缺点
- 回调地狱
- 高度耦合
- 不易维护
- 不能直接return
# 事件驱动
优点
- 去耦合
- 便于实现模块化
缺点
- 运行流程不清晰
- 阅读代码困难
代码示例
// login.js
let loginEvent = new CustomEvent("login-over", {
token: "token"
});
function login() {
setTimeout(() => {
window.dispatchEvent(loginEvent);
}, 3000);
}
// getOrderId.js
function getOrderId(token) {
if(token){
setTimeout(() => {
window.dispatchEvent(orderIdEvent);
}, 2000);
}
}
function tokenListener(ev) {
getOrderId(ev.token);
}
//在window 上添加监听事件
window.addEventListener("login-over", tokenListener);
# 发布订阅
也是使用事件驱动,但是有一个事件中心,可以查看消息流转。
// MsgCenter.js
/*
* 消息中心
* @class MsgCenter
*/
class MsgCenter {
constructor() {
this.listeners = {};
}
/**
*
*
* 订阅
* @memberOf MsgCenter
*/
subscribe(type, listener) {
if (this.listeners[type] === undefined) {
this.listeners[type] = [];
}
this.listeners[type].push(listener);
console.log(`${type}消息订阅数:${this.listeners[type].length}`);
return listener;
}
/**
*
*
* 发送
* @memberOf MsgCenter
*/
dispatch(type, args = {}) {
if (!type) {
throw new Error("Event object missing 'type' property.");
}
if (this.listeners[type] instanceof Array) {
const listeners = this.listeners[type];
for (let j = 0; j < listeners.length; j++) {
listeners[j].call(this, type, args);
}
}
}
/**
*
*
* 取消订阅
* @memberOf MsgCenter
*/
unSubscribe(type, listener) {
if (this.listeners[type] instanceof Array) {
const listeners = this.listeners[type];
for (let i = 0; i < listeners.length; i++) {
if (listeners[i] === listener) {
listeners.splice(i, 1);
break;
}
}
console.log(`${type}消息订阅数:${this.listeners[type].length}`);
}
}
/**
*
* 获取某种消息所有订阅
* @param {any} type
* @returns
*
* @memberOf MsgCenter
*/
getTypeSubscribe(type) {
return this.listeners[type] || [];
}
/**
*
*
* 销毁
* @memberOf MsgCenter
*/
destroy() {
this.listeners = null;
}
}
const MyMsgCenter = new MsgCenter();
export default MyMsgCenter;
// login.js
import MyMsgCenter from "./MsgCenter.js";
export function login() {
setTimeout(() => {
MyMsgCenter.dispatch("login-over",{ token:"token" });
}, 3000);
}
// getOrderId.js
import MyMsgCenter from "./MsgCenter.js";
function getOrderId(token) {
if(token){
console.log(token)
}
}
function tokenListener(type,ev) {
getOrderId(ev.token);
MyMsgCenter.unSubscribe(type, tokenListener);
}
MyMsgCenter.subscribe("login-over", tokenListener);
# Promise
优点
链式调用,流程清晰
缺点
- 代码冗余,不够简洁
- 无法取消Promise
- 错误需要回调函数捕获
# Generator
- 优点:可以控制函数执行
- 缺点:执行时机太麻烦
function login() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("token");
}, 3000);
});
}
function getOrderId(token) {
return new Promise((resolve, reject) => {
if (token) {
setTimeout(() => {
resolve("orderId");
}, 2000);
}
});
}
function orderDetails(orderId) {
return new Promise((resolve, reject) => {
if (orderId) {
setTimeout(() => {
resolve("淘宝订单:购买xxx书一本");
}, 1500);
}
});
}
function* execute() {
const token = yield login();
const orderId = yield getOrderId(token);
const orderInfo = yield orderDetails(orderId);
}
let g = execute();
let { value, done } = g.next();
value.then((token) => {
console.log("token==", token);
let { value, done } = g.next(token);
value.then((orderId) => {
console.log("orderId==", orderId);
let { value, done } = g.next(orderId);
value.then((orderInfo) => {
console.log("orderInfo==", orderInfo);
});
});
});
# Async&Await
TIP
- Async函数 是Generator函数的语法糖
- 语义更好,内置执行器
- 缺点:蝴蝶效应 一处async 一处await
function login() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("token");
}, 3000);
});
}
function getOrderId(token) {
return new Promise((resolve, reject) => {
if (token) {
setTimeout(() => {
resolve("orderId");
}, 2000);
}
});
}
function orderDetails(orderId) {
return new Promise((resolve, reject) => {
if (orderId) {
setTimeout(() => {
resolve("淘宝订单:购买xxx书一本");
}, 1500);
}
});
}
async function execute() {
const token = await login();
const orderId = await getOrderId(token);
const orderInfo = await orderDetails(orderId);
console.log(orderInfo);
}
execute();
← ES5创建对象继承 深入理解Promise →