实现async/await

2019-09-28  本文已影响0人  videring

generator函数

Iterator接口

typescript的接口描述如下:遍历器接口(Iterable)、指针对象(Iterator)和next方法返回值

interface Iterable {
  [Symbol.iterator]() : Iterator,
}

interface Iterator {
  next(value?: any) : IterationResult,
}

interface IterationResult {
  value: any,
  done: boolean,
}

-ES6 的有些数据结构原生具备 Iterator 接口(比如数组),即不用任何处理,就可以被for...of循环遍历。原因在于,这些数据结构原生部署了Symbol.iterator属性(详见下文),另外一些数据结构没有(比如对象)。凡是部署了Symbol.iterator属性的数据结构,就称为部署了遍历器接口。调用这个接口,就会返回一个遍历器对象

调用 Iterator 接口的场合

let generator = function* () {
  yield 1;
  yield* [2,3,4];
  yield 5;
};

var iterator = generator();

iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }

for...in循环有几个缺点。

数组的键名是数字,但是for...in循环是以字符串作为键名“0”、“1”、“2”等等。
for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
某些情况下,for...in循环会以任意顺序遍历键名。
总之,for...in循环主要是为遍历对象而设计的,不适用于遍历数组。
看了好几遍阮一峰的es6语法才看懂
Generator 函数返回一个遍历器 这个遍历器提供 next() 方法来控制Generator函数的执行,暂停 。
yield 表达式 暂停的标志

简易版本的Generator函数遍历器自执行函数:

// 协程 callback版本
var timeout = (time)=>{
  return (callbck)=>{
       setTimeout(()=>{
      console.log('time',time)
      callbck()
    },time)
  }
}

// Generator 遍历器生成函数
function* callbackGenerator() {
  var res = yield timeout(2000) // 使得 yield 的value 是一个callback 自执行递归 使下一次的next在callback里面执行
  var res1 = yield timeout(2000)
}

// callback版本  版本自执行函数
function run (Generator) {
  var hw = Generator();
 const  next = ()=>{
   const aa = hw.next()
   if(!aa.done){
    aa.value(next) 
   }else{
     return true
   }
 }
 next()
}

run(callbackGenerator)

// 协程 promise 版本
var timeout = (time)=>{
  return new Promise((resolve)=>{
       setTimeout(()=>{
      console.log('time',time)
      resolve(time+2000)
    },time)
  })
}

// Generator 遍历起器生成函数
function* callbackGenerator() {
  var res = yield timeout(2000) // 使得 yield 的value是promise 自执行时把下一次的next在then里面执行
  var res1 = yield timeout(res)
}

// promise版本 版本自执行函数
function run (Generator) {
  var hw = Generator();
 const  next = (query)=>{
   var aa = hw.next(query)
   if(!aa.done){
    aa.value.then(next) 
   }else{
     return true
   }
 }
 next()
}

run(callbackGenerator)

核心思想:利用generator遍历器生成器函数的分段执行 ,只有在遍历器对象 执行next方法之后交出了控制权 ,在完成后 callback || promise.then()里面调用下一次next的时候又继续恢复控制权这个功能来实现的

async await 正式利用了这一点

两种方法可以做到这一点。
(1)回调函数。将异步操作包装成 Thunk 函数,在回调函数里面交回执行权。

(2)Promise 对象。将异步操作包装成 Promise 对象,用then方法交回执行权。
from http://es6.ruanyifeng.com/#docs/generator-async

es7 async await 异步写法

function sleep(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms);
  });
}

async function test() {
  for (let i = 0; i < 10; i++) {
    await sleep(100);
  }
}

转化成es6是下边这样
async await 实际上是由 generator + yield 控制流程 + promise 实现回调

// _asyncToGenerator 顾名思义转换async to Generator

function _asyncToGenerator(fn) {
  return function () {
    var gen = fn.apply(this, arguments);
    return new Promise(function (resolve, reject) {
      function step(key, arg) {
        try {
          var info = gen[key](arg);
          var value = info.value;
        } catch (error) {
          reject(error);
          return;
        }
        if (info.done) {
          resolve(value);
        } else {
          return Promise.resolve(value).then(function (value) {
            return step("next", value);
          },
            function (err) {
              return step("throw", err);
            });
        }
      }
      return step("next");
    });
  };
}

function sleep(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms);
  });
}

let test = function () {
  var ref = _asyncToGenerator(function* () {
    for (let i = 0; i < 10; i++) {
      yield sleep(100);
    }
  });

  return function test() {
    return ref.apply(this, arguments);
  };
}();

参考:https://www.jianshu.com/p/862ab6d1a2f6

上一篇 下一篇

猜你喜欢

热点阅读