IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Node 4.4.x 里面尝试async / await

    ankyhe发表于 2016-06-26 11:42:43
    love 0

    什么是async/await

    async/await 的灵感来自于C#,是ES7的一部分。async/await是一种方法,可以让我们不用写callback,想同步方式那样使用函数。下面是一个例子:

    import 'request' from request;
    function requestPromise(config, acceptStatusCode = (statusCode) => statusCode === 200) {
      let promiseCallbackAF;
      return new Promise(promiseCallbackAF = (fullfil, reject) => {
        let responseCallbackAF;
        request(config, responseCallbackAF = (err, response) => {
          if (err) {
            return reject(new RequestError(err));
          }
          if (!acceptStatusCode(response.statusCode)) {
            return reject(new ResponseStatusError('Response status code is not accepted.', response));
          }
          return fulfill(response);
        });
      });
    }
    
    async function main() {
      const response = await requestPromise({url:'http://www.baidu.com'});
      console.log('response is %s', response.body.substr(0, 100));
      return 0;
    }
    
    main();
    

    怎样在Node 4.4.x里面使用async/await

    现在的Node 4.4.x (甚至是Node 6.x) 都不支持async/await, 请查阅:http://kangax.github.io/compat-table/esnext/ 。但是我们可以通过Babel来支持。

    $ npm install babel-plugin-transform-async-to-module-method --save-dev
    $ npm install babel-preset-es2015-node4 --save-dev
    $ npm install babel-preset-stage-3 --save-dev
    $ npm install bluebird --save 
    

    并且使用下面的.babelrc文件

    {
      "presets": ["es2015-node4", "stage-3"],
      "plugins": [["transform-async-to-module-method", {
        "module": "bluebird",   
        "method": "coroutine"
      }], "transform-es2015-parameters"]
    }
    

    错误处理

    async function foo(url) {
      return await requestPromise({url});
    }
    
    async function main() {
      const response = await foo('http://www.macx.cn/no-page');
      console.log('response is %s', response.substr(0, 100));
    }
    

    之后运行程序可以发现程序会打印出所有的callstack(这个非常非常有用)

    Unhandled rejection Error: Response status code 404 is not accepted.
        at ResponseStatusError (test.js:16:5)
        at Request.responseCallbackAF [as _callback] (test.js:37:23)
        at Request.self.callback (/Users/ankyhe/work/tools/health-test/node_modules/request/request.js:200:22)
        at emitTwo (events.js:87:13)
        at Request.emit (events.js:172:7)
        at Request.<anonymous> (/Users/ankyhe/work/tools/health-test/node_modules/request/request.js:1067:10)
        at emitOne (events.js:82:20)
        at Request.emit (events.js:169:7)
        at IncomingMessage.<anonymous> (/Users/ankyhe/work/tools/health-test/node_modules/request/request.js:988:12)
        at emitNone (events.js:72:20)
        at IncomingMessage.emit (events.js:166:7)
        at endReadableNT (_stream_readable.js:913:12)
        at nextTickCallbackWith2Args (node.js:442:9)
        at process._tickDomainCallback (node.js:397:17)
    From previous event:
        at foo (/Users/ankyhe/work/tools/health-test/test.js:10:16)
        at test.js:49:26
        at [object Generator].next (native)
    From previous event:
        at main (/Users/ankyhe/work/tools/health-test/test.js:20:16)
        at Object.<anonymous> (test.js:53:1)
        at Module._compile (module.js:409:26)
        at loader (/Users/ankyhe/work/tools/health-test/node_modules/babel-cli/node_modules/babel-register/lib/node.js:158:5)
        at Object.require.extensions.(anonymous function) [as .js] (/Users/ankyhe/work/tools/health-test/node_modules/babel-cli/node_modules/babel-register/lib/node.js:168:7)
        at Module.load (module.js:343:32)
        at Function.Module._load (module.js:300:12)
        at Function.Module.runMain (module.js:441:10)
        at /Users/ankyhe/work/tools/health-test/node_modules/babel-cli/lib/_babel-node.js:160:24
        at Object.<anonymous> (/Users/ankyhe/work/tools/health-test/node_modules/babel-cli/lib/_babel-node.js:161:7)
        at Module._compile (module.js:409:26)
        at Object.Module._extensions..js (module.js:416:10)
        at Module.load (module.js:343:32)
        at Function.Module._load (module.js:300:12)
        at Function.Module.runMain (module.js:441:10)
        at startup (node.js:139:18)
        at node.js:968:3
    

    最后的问题

    大家可以看到上面这种处理方式非常非常像“传统” Java / Python/ Ruby 的编码方式,但是,请务必注意异常处理的方式。不要在v8里面写这样的代码:

    function foo() {
      try {
        // code 1
        // code 2 
        // code 3
      catch (err) {
        // exception handler
      }
    }
    

    这样的代码v8是不能优化的,比较好的方式是:

    function bar() {
      // code 1
      // code 2
      // code 3
    }
    function foo() {
      try {
        foo();
      } catch (err) {
         // exception handler
      }
    }
    

    但是,其实很多都建议不要在node里面使用异常处理 所以我们只好选择另外一种方式:

    function requestPromise(config, acceptStatusCode = (statusCode) => statusCode === 200) {
      let promiseCallbackAF;
      return new Promise(promiseCallbackAF = (fulfill) => {
        let responseCallbackAF;
        request(config, responseCallbackAF = (err, response) => {
          if (err) {
            return fulfill({err: new RequestError(err)});
          }
          if (!acceptStatusCode(response.statusCode)) {
            return fulfill({err: new ResponseStatusError(`Response status code ${response.statusCode} is not accepted.`, response)});
          }
          return fulfill({response});
        });
      });
    }
    
    async function foo(url) {
      return await requestPromise({url});
    }
    
    async function main() {
      const {err, response} = await foo('http://www.macx.cn/no-page');
      if (err) {
        return console.log('Failed for request due to: %s\n%s', err, err.stack);
      }
      console.log('response is %s', response.substr(0, 100));
      return 0;
    }
    

    这种方式其实就是同步化的callback (在node里面,默认的callback都是(err, data)这样的)。如果这个promise不是你自己的,而是别人生成的,我们也可以包装一下,

    function makeNoRejectPromise(promise) {
      return new Promise(fulfill) {
        promise.then(function success(data) {
    	  return fullfil({data});
    	}, function failure(err) {
    	  return fulfill({err});
        });
      }
    }
    

    这种做法现阶段还不错,只要在自己的代码里面遵循这个方式就好了。但是对于整个社区的编码风格,还是用异常可能更好一些。所以希望v8早日可以更好的支持异常的优化。



沪ICP备19023445号-2号
友情链接