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状态不可逆

Promise实现方式
简易版
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~

原文地址:https://www.cnblogs.com/moran1992/p/14730219.html