js-challenges icon indicating copy to clipboard operation
js-challenges copied to clipboard

await async 如何实现

Open lxy-Jason opened this issue 3 years ago • 3 comments

function asyncToGenerator(generatorFunc) {
  //传入一个生成器函数
  //返回一个新的函数
  return function () {
    //先调用generator函数生成<迭代器>
    const gen = generatorFunc.apply(this, arguments);
    //返回一个promise
    return new Promise((resolve, reject) => {
      //内部定义一个step函数来源 用来一步步跨过yield的阻碍
      //key有next和throw两种取值,分别对应了gen的next和throw方法
      //arg参数则是用来promise resolve得带的值交给下一个yield
      function step(key, arg) {
        let generatorResult;

        try {
          generatorResult = gen[key](arg);
        } catch (err) {
          return reject(err);
        }
        //gen.next()得到的结果是一个{value,done}的结构
        const { value, done } = generatorResult;
        if (done) {
          //已经完成
          return resolve(value);
        } else {
          return Promise.resolve(
            //对value不是promise的情况包裹一层
            value //这个value对应的是yield后面的promise
          ).then(
            function onResolve(val) {
              step("next", val);
            },
            function onReject(err) {
              step("throw", err);
            }
          );
        }
      }
      step("next"); //第一次调用next
    });
  };
}
function fn(nums) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(nums * 2);
    }, 1000);
  });
}
function* gen() {
  const num1 = yield fn(1);
  console.log(num1); // 2
  const num2 = yield fn(num1);
  console.log(num2); // 4
  const num3 = yield fn(num2);
  console.log(num3); // 8
  return num3;
}
const testGAsync = asyncToGenerator(gen);
// 返回的是一个函数,函数调用返回一个promise
testGAsync().then(res => {
    console.log(res);
});
//对应上面的gen()
async function asyncFn() {
  const num1 = await fn(1);
  console.log(num1); // 2
  const num2 = await fn(num1);
  console.log(num2); // 4
  const num3 = await fn(num2);
  console.log(num3); // 8
  return num3;
}
asyncFn()

源码来源

lxy-Jason avatar Nov 06 '22 07:11 lxy-Jason

function* generatorFunc() {
   const data1 = yield getData()
   console.log('data1', data1);
   const data2 = yield getDataTwo()
   console.log('data2', data2);
}
// 自动执行 
function autoGenerateFunc(generatorFunc) {
   return function () {
       // 生成迭代器
       const gen = generatorFunc.apply(this, arguments)
       return new Promise((resolve, reject) => {
           const step = (p, arg) => {
               let genObj;
               try {
                   genObj = gen[p](arg)
               } catch (error) {
                   return reject(error)
               }
               const { value, done } = genObj;
               if (done) {
                   return resolve(value)
               } else {
                   return Promise.resolve(value).then(val => step('next', val), err => step('throw', err))
               }
           }
           step('next')
       })
   }
}

LifeIsTerrible avatar Feb 27 '23 13:02 LifeIsTerrible

let getData = () => { let random = Math.random() return new Promise((resolve, reject) => setTimeout(() => { random > 0.9 ? resolve('成功的数据') : reject('失败的数据') }, 1000) ) } // 实现async 和 await async function c() { const data1 = await getData() console.log(data1, '我是data1') const data2 = await getData() console.log(data2, '我是data2') } // console.log(c()) function asyncToGenerator(asyncToGenerator) { let gen = asyncToGenerator() return new Promise((resolve, reject) => { function step(key, data) { let result try { result = genkey // 如果key为throw,并且generator函数没有捕获的话,会直接结束。如果有捕获的话,跳到下一个yield关键处 } catch (error) { return reject(error) } const { done, value } = result if (done) { resolve(value) } else { Promise.resolve(value).then( (data) => { step('next', data) }, (error) => { step('throw', error) } ) } } step('next') }) } function* generator() { try { const data1 = yield getData() console.log(data1, '我是data1') const data2 = yield getData() console.log(data2, '我是data2') } catch (error) {} return '333' } console.log(asyncToGenerator(generator))

cscty avatar Jul 04 '23 09:07 cscty

function autoGenerateFunc(fn) {
  return function() {
    const gen = fn.apply(this, arguments);
    const step = function(v) {
      const {done, value} = gen.next(v);
      if (done) {
        return Promise.resolve(value);
      } else {
        return Promise.resolve(value).then((data)=>step(data), (err) => {gen.throw(err)});
      }
    }
    step();
  }
}

function getData(nums) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(1);
    }, 1000);
  });
}

function getDataTwo(nums) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(2);
    }, 1000);
  })
}

function* generatorFunc() {
  const data1 = yield getData()
  console.log('data1', data1);
  const data2 = yield getDataTwo()
  console.log('data2', data2);
}

const autoGenerate = autoGenerateFunc(generatorFunc);
autoGenerate();

Windseek avatar Nov 12 '24 02:11 Windseek