梳理全部前端异步解决方案

众所周知js是单线程,从头跑到尾而后不停的事件循环,可是浏览器是多线程的,全部前端全部的异步能够概括为,js的事件循环在根据标准不停的先后执行不一样异步线程的回调前端

其实如今js对于异步的全部解决方案不论是async 仍是 promise 仍是监听什么的归根结底都是回调触发,而咱们至今为异步所做的全部努力不过是让异步回调写的更加像同步一些 目前前端对异步的处理大体通过这三个阶段ios

1 纵向无限回调,好比ajax的回调ajax

2 promise 经过then链式回调,好比axios等axios

3asyns 经过promise在resolve中交换控制权来自动执行的迭代器来让异步变得看起来像同步api

无限回调就不讲了,每一个回调函数以前相互依赖造成强耦合从而使代码纵向发展变成一坨代码数组

直接从promise开始,promise其实就是回调换了一种写法而已,也就是对回调多了一层封装 简单来说就是他是一个原生提供的js对象,接受一个函数做为参数来生成实例,这个函数又以resolve,reject这两个函数做为参数promise

一共有三种状态分别是进行中(pending)已解决(fulfilled)已失败(rejected)浏览器

而后咱们日常说的什么把一个异步回调封装成promise什么的听起来高大上不过就是,你本身根据回调函数的结果,自行选择执行resolve(将状态从pending转换成fulfilled)或者reject(将状态从pending转换成rejected)bash

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
复制代码

而后他有一个最重要也是用的最多的一个方法**then()**他接受两个函数做为参数分别做为上面说的resolve,reject执行完成后的回调参数,而参数则是则是由resolve传入数据结构

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操做成功 */){
  console.log('结果:')
    resolve('123');
  } else {
    reject('321');
  }
});
promise.then(x=>{
    console.log(x)
},y=>{
    console.log(y)
}
)

//结果:
123
321
复制代码

同时then()也是返回一个promise对象因此能够继续链式回调,上一个then()方法return的参数能够做为下一个then()方法的参数 除此以外还有all(),race()之类的辅助方法,都是些顾名思义的api

其实从本质上来讲promise就是回调换了一种写法,在回调发生之时去修改promise的内部状态,而后经过不一样的状态,来去决定执行then()里面的哪一个方法,当业务逻辑复杂起来的时候,你特么不照样不停的then(),也很丑啊!

因此出现了async 和 await 写起来感受和同步差很少,又美观又好看,妈妈不再用担忧我代码丑了,虽然看起来高大上其实本质仍是回调,在我看来最大的好处不过是开发体验的提高而已

首先要明白的是 async 不过是 Generator的语法糖,而Generator本质是个不能自动执行的迭代器,那么问题来了什么是js的迭代器呢?

迭代器本质是来讲是一个指针对象指向数据结构的起始位置,经过调用next()方法使其指向下一个存储单元,且访问该数据的描述信息

像在js中[]就原生装载了遍历器接口,访问数组实例的[Symbol.iterator]属性,便会返回该数据结构的遍历器对象,而后调用这个对象的next()方法便会依次返回该数据机构各个位置的描述信息

let a = [1,2]
 let i = a[Symbol.iterator]();
 console.log(i.next())
 
 返回:{value: 1, done: false}
复制代码

Generator 函数,即是返回这么一个遍历器对象,经过调用.next()方法来返回他内部保存的状态,因此你也能够叫他状态保存机

function* generator(){
		   yield 1;
		   yield 2;
		   return 3;
		}
		let g = generator()
		g.next()
		
		返回  { value: 1, done: false }...
复制代码

他之因此能被用在异步应用中的一个关键属性是:你能够经过next()传值来做为上一步操做所产生的结果值,这样咱们就能够经过外部输入的参数值不一样来对Generator的执行进行干预,从而达到交换执行权的效果

function* generator(){
		   yield 1;
		   let x = yield 2;
		   console.log(x)
		   return 3;
		}
		let g = generator()
		g.next(5)
		
		返回  { value: 1, done: false },5
复制代码

那咱们要作的就是让Genrator自动执行,一直到最后一个状态,好比这样:

function* generator(){
		   yield 1;
		   yield 2;
		   return 3;
		}
		let g = generator()
		if(!g.next().done){
		    g.next()
		}
复制代码

可是这样作不到咱们想要的异步操做,咱们想要的效果是,在上一步异步操做执行成功的后执行下一步异步操做,那么咱们的思路就是提供一个方法,让他能够自动的执行generator,在每个异步操做经过yield语句将函数的执行权过分给异步方法,同时generator外部咱们能够经过获取到异步函数的返回结果来决定是否启用下一步,若是异步执行成功,咱们再将函数的执行权交还给generate方法。以前咱们说过promise,那么若是咱们把每个异步操做都封装成promise对象,这样咱们就能够尝试着写一个自动执行的方法

function run(gen){
  var g = gen();

  function next(data){
    var result = g.next(data);
    if (result.done) return result.value;
    result.value.then(function(data){
      next(data);
    });
  }

  next();
}

run(gen);
复制代码

由于yield返回的是一个Promise对象,那么咱们在调用next()方法时将获取到这个对象,以前咱们说过promise的then方法接受两个方法做为参数分别做为执行成功和执行失败的回调函数,那么咱们就只须要在执行成功的那个方法也就是第一个传入的函数执行next()方法那么若是每一步异步操做都正常执行的话那么整个generator方法将自动执行,async机制就是自带了一个能够判断promise状态的执行器,能够在await的时候将resolve的值给return 回来

相关文章
相关标签/搜索