详解ES7的async及webpack配置async

项目中有个需求,类似视频网站下载视频,比如有5个case,每个case有数量不等的的video需要从服务端下载,并且video的下载顺序是串联的,只有当正在下载的case下载完才能下载另外一个case,否则下一个case处于wait状态。

如何解决此问题

  • 使用Promise
    利用promise的then方法,但是因为无法确定每个case的video的数量,导致不能确定后面应该接几个then,最开始想到一个笨方法,列一个表格把所有可能的video数量都列出来(因实际需求每个case不会超过10个video),然后去套用不同的方法,
function downVideoSeries(n) {
  if(n === 1) {
    return new Promise((resolve, reject) =>{
      //ajax code for one video
    }).then((resolve)=>{
      ...
    }).catch((err)=>{
      ...
    })
  }else if(n ===2) {
    return new Promise((resolve, reject) =>{
      //ajax code for one video
    }).then((resolve)=>{
      new Promise((resolve, reject) =>{
        //ajax code for another video
      })
    }).then((resolve)=>{
      ...
    }).catch((err)=>{
      ...
    })
  }
  ...
}

后经重新查看Promise,可以发现能构造一个空的Promise来解决问题,动画一帧帧执行的代码

function chainAnimationsPromise(elem, animations) {

  // 变量ret用来保存上一个动画的返回值
  let ret = null;

  // 新建一个空的Promise
  let p = Promise.resolve();

  // 使用then方法,添加所有动画
  for(let anim of animations) {
    p = p.then(function(val) {
      ret = val;
      return anim(elem);
    });
  }

  // 返回一个部署了错误捕捉机制的Promise
  return p.catch(function(e) {
    /* 忽略错误,继续执行 */
  }).then(function() {
    return ret;
  });

}
  • 流程控制终极大法: async

async会将其后的函数(函数表达式或lamada)的返回值封装成一个Promise对象,所以获取async返回值用then调用。

async中的await用同步的方式来执行异步流,并且是阻塞的,只有当前的await执行,流程才会走向下一个。很适合此项目需求,因之前未用过,故配置webpack也遇到了坑。类似代码

async startDownPerCase() {
try{
     for(let i=0; i<len; i++) {
       let url = 'xhr.url';
       //异步请求
       await self.doBlobGet(url, ...args)
       .then(()=>{
         //成功回调
         ....
       }).catch((err)=>{
         //失败回调
         ...
       });
     }
   } catch(e) {
     console.log(`[downPerCaseError], ${e}`);
   }
}

在react+webpack中使用async

项目架构为webpack+react+es6。未配置的情况下,执行会输出错误提示Babel 6 regeneratorRuntime is not defined,查阅stackoverflow,需要进行配置

  • npm install babel-preset-stage-3 和 npm install babel-polyfill

  • webpack.config.js中entry添加 [‘babel-polyfill’, __dirname + ‘/router.js’]

  • bable的presets设置为presets: ['es2015', 'stage-3', 'react']

  • eslint设置为如下,把版本改成8,保证不报error错误

"parserOptions": {
        "ecmaVersion": 8,
        "sourceType": "module",
        "ecmaFeatures": {
            "jsx": true
        }
    }

还有另外一种解决方案,使用 babel-plugin-transform-runtime

参考 https://stackoverflow.com/questions/33527653/babel-6-regeneratorruntime-is-not-defined

async的用法

async函数返回一个 Promise 对象,可以使用then方法添加回调函数

返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数

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

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

await 命令

正常情况下,await命令后面是一个 Promise 对象。如果不是,会被转成一个立即resolve的 Promise 对象。

async function f() {
  return await 123;
}

f().then(v => console.log(v))
// 123

只要一个await语句后面的 Promise 变为reject,那么整个async函数都会中断执行。

async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}

所以一般会使用try catch来捕获错误

async function f() {
  try {
    await new Promise().then(()=>{}).catch(()=>{});
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

如果有多个await命令,可以统一放在try…catch结构中。

async function main() {
  try {
    const val1 = await firstStep();
    const val2 = await secondStep(val1);
    const val3 = await thirdStep(val1, val2);

    console.log('Final: ', val3);
  }
  catch (err) {
    console.error(err);
  }
}

async语法参考阮一峰大神写的http://es6.ruanyifeng.com/#docs/async#基本用法

猜你喜欢

转载自blog.csdn.net/wkyseo/article/details/78210599