Javascript异步解决方案总结
1.回调函数(callback)
思想:
通过参数传入回调函数,未来调用回调函数是让函数的条用着判断了发生了什么
优点:
容易实现,容易部署
缺点:
可读性变差,容易出现回调地狱
栗子
function a(cb) { console.log("a"); cb(c); } a(b); function b(cb) { console.log("b"); cb(); } function c() { console.log("c"); }
我们只写了三个函数可读性就变得极差,出现回调地狱问题
2.事件的发布订阅
思想:
回调函数的事件化,任务执行不取决于代码执行顺序,取决于某个事件是否发生。
优点:
容易理解,可以绑定多个事件,每个事件可以指定多个回调函数
缺点:整个程序变成了事件驱动,运行流程混乱变差
栗子
function Events() { if (!this instanceof Events) return new Events(); this.events = {}; } Events.prototype.register = function(name, fn) { this.events[name] = fn; }; Events.prototype.fire = function(name) { events[name](); }; const ins = new Events(); ins.register("dqhan", function() {}); ins.fire("dqhan");
可以随意注册事件,随意执行,虽然灵活但是也导致代码流程混乱,举个场景,组件消息传递,通过父级,如果我们使用了这种事件驱动的方式,是不是就不能直观的看到数据流向问题,如果全都用何种方式实现呢,阅读代码将非常混乱。
3.延迟函数
jQuery提出的思想Deferred延迟函数
思想:
通过deferred对象对异步操作进行状态绑定,deferred对象统一提供API,对各种异步操作的状态进行操作(成功、失败、进行中)
优点:避免了层层嵌套的回调函数, deferred对象统一提供接口,是的控制异步操作更加容易
缺点:状态不可逆,从待定状态切换到另一个状态后,再次调用resolve或者reject对原状态讲不起任何作用。
特点:外部可以修改deferred的状态
栗子
var dtd = $.Deferred(); var wait = function(dtd) { var tasks = function() { dtd.resolve(); }; setTimeout(tasks, 100); return dtd; }; $.when(wait(dtd)) .done(function() {}) .fail(function() {}); dtd.resolve(); // 外部随意修改defererd的状态
4.(继承了Deferred的设计思想)Promise
ES6提供的异步标准,原生提供了Promise对象
思想: 一个容器,里面保存着一个异步操作的结果。从语法上来看,Promise是一个对象,提供了统一的API,各种异步操作都可以及使用同样的方法处理
优点:与deferred一样
缺点:与deferred一样
Promise与Deferred的区别
1.回调API不一样
2.promise状态不可以在外面随意修改
promise三种状态:
pending,resolved,rejected
promise创建时默认状态为pending状态,当执行了对应的resolve或者reject函数时,修改对应状态
var promise = new Promise(function(resolve, reject) { resolve(value); reject(error); });
修改完状态执行相应的api
var promise = new Promise(function(resolve, reject) { resolve(value); reject(error); }) .then(res => { console.log("resolve"); }) .catch(e => { console.log("reject"); });
promise链式调用
var promise = new Promise(function(resolve, reject) { resolve(""); }) .then(res => { return Promise.resolve({ name: "dqhan" }); }) .then(res => { console.log(res); });
解决callback回调地狱问题
Promise对象特点:
1状态不受外界影响
2状态不可逆
class Promise { callbacks = []; state = "pending"; value = null; constructor(fn) { fn(this._resolve.bind(this)); } then(onFulfilled) { if (this.state === "pending") { this.callbacks.push(onFulfilled); } else { onFulfilled(this.value); } } _resolve(value) { this.state = "fulfilled"; this.value = value; this.callbacks.forEach(fn => fn(value)); } }
添加链式调用
class Promise { callbacks = []; state = "pending"; value = null; constructor(fn) { fn(this._resolve.bind(this)); } then(onFulfilled) { if (this.state === "pending") { this.callbacks.push(onFulfilled); } else { onFulfilled(this.value); } return this; } _resolve(value) { this.state = "fulfilled"; this.value = value; this.callbacks.forEach(fn => fn(value)); } }
在then中return了一个this,乍一看是对的,但是仔细想想,是不是整个链式调用返回的都是同一个对象,违背了Promise对象的意图,所以改进
class Promise { callbacks = []; state = "pending"; value = null; constructor(fn) { fn(this._resolve.bind(this)); } then(onFulfilled) { return new Promise(resolve => { this._handle({ onFulfilled: onFulfilled || null, resolve: resolve }); }); } _handle(callback) { if (this.state === "pending") { this.callbacks.push(callback); return; } if (!callback.onFulfilled) { callback.resolve(this.value); return; } var ret = callback.onFulfilled(this.value); callback.resolve(ret); } _resolve(value) { if (value && (typeof value === "object" || typeof value === "function")) { var then = value.then; if (typeof then === "function") { then.call(value, this._resolve.bind(this)); return; } } this.state = "fulfilled"; this.value = value; this.callbacks.forEach(callback => this._handle(callback)); } }
Over~