Node.js 8 于上个月月底正式发布,带来了不少新特性。其中比较值得注意的,便有 util.promisify()
这个方法。javascript
若是你已经很熟悉 Promise,请继续往下看。若是你还不熟悉 Promise,能够先跳过去看下下章:Promise 介绍。html
util.promisify()
虽然 Promise 已经普及,可是 Node.js 里仍然有大量依赖回调的异步函数,若是咱们把每一个函数都封装一遍,那真是齁麻烦齁麻烦的,比齁还麻烦。java
因此 Node.js 8 就提供了 util.promisify()
这个方法,方便咱们把原来的异步回调方法改为支持 Promise 的方法,接下来,想继续 .then().then().then()
搞队列,仍是 await 就看实际须要了。node
咱们看下范例,让读取目录文件状态的 fs.stat
支持 Promise:jquery
const util = require('util'); const fs = require('fs'); const stat = util.promisify(fs.stat); stat('.') .then((stats) => { // Do something with `stats` }) .catch((error) => { // Handle the error. });
怎么样,很简单吧?按照文档的说法,只要符合 Node.js 的回调风格,全部函数均可以这样转换。也就是说,只要知足下面两个条件,不管是否是原生方法,均可以:git
最后一个参数是回调函数github
回调函数的参数为 (err, result)
,前面是可能的错误,后面是正常的结果小程序
一样是上面的例子,若是想要结合 Await/Async,能够这样使用:segmentfault
const util = require('util'); const fs = require('fs'); const stat = util.promisify(fs.stat); async function readStats(dir) { try { let stats = await stat(dir); // Do something with `stats` } catch (err) { // Handle the error. console.log(err); } } readStats('.');
那若是现有的使用回调的函数不符合这个风格,还能用 util.promisify()
么?答案也是确定的。咱们只要给函数增长一个属性 util.promisify.custom
,指定一个函数做为 Promise 化处理函数,便可。请看下面的代码:api
const util = require('util'); // 这就是要处理的使用回调的函数 function doSomething(foo, callback) { // ... } // 给它增长一个方法,用来在 Promise 化时调用 doSomething[util.promisify.custom] = function(foo) { // 自定义生成 Promise 的逻辑 return getPromiseSomehow(); }; const promisified = util.promisify(doSomething); console.log(promisified === doSomething[util.promisify.custom]); // prints 'true'
如此一来,任什么时候候咱们对目标函数 doSomething 进行 Promise 化处理,都会获得以前定义的函数。运行它,就会按照咱们设计的特定逻辑返回 Promise 实例。
咱们就能够升级之前全部的异步回调函数了。
由于种种历史缘由,JS 当中有大量异步函数。这些异步函数,大多要依赖回调进行处理(这里我以为把事件侦听算做回调也是合理的),可是回调嵌套层次一多,就会造成所谓的“回调陷阱”,让开发者苦不堪言。
为了解决这个问题,开发社区通过摸索,总结出来一套名为 Promise/A+ 的解决方案。大致上来讲,这套方案经过使用 “Promise 回调实例”包裹原先的回调函数,能够将原先复杂的嵌套展开、铺平,从而下降开发和维护的难度和成本。
new Promise( (resolve, reject) => { // 构建一个 Promise 实例 someAsyncFunction( (err, result) => { // 调用原来的异步函数 if (err) { // 发生错误,进入错误处理模式 return reject(err); } resolve(result); // 一切正常,进入队列的下一环节 }); }) .then( result => { // 下一环节 return doSomething(result); }) .then( result2 => { // 又下一环节 return doSomething2(result2); }) ... // 各类中间环节 .catch( err => { // 错误处理 console.log(err); });
ES2015(ES6)里包含了 Promise 标准,现在已经在大部分运行时里实装,咱们能够放心大胆的使用它。并且,因为 Promise 不须要新的语法元素,因此即便在不支持原生 Promise 的环境里也可使用类库,好比 Q 或者 Bluebird,甚至 jQuery。
在小程序里也有效哟!
ES2017 增长了 Await/Async 语法,但请注意,Await
后面必须跟 Promise 实例才能实现异步。因此,你们仍是把 Promise 的概念学好吧!
function resolveAfter2Seconds(x) { return new Promise(resolve => { setTimeout(() => { resolve(x); }, 2000); }); } async function f1() { var x = await resolveAfter2Seconds(10); console.log(x); // 10 } f1();
例子来源于 MDN。
若是你想进一步学习使用 Promise,强烈推荐个人此次分享:Promise 的 N 种用法。能够帮助你一站式的学会使用 Promise。
PS2:刚才看到 Node.js 已经发布 8.1 了,真快呀……新版本的 Changelog 在这里,已修复为主。
同步发于 个人博客