Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何将现有回调API转换为承诺?_Javascript_Node.js_Callback_Promise_Bluebird - Fatal编程技术网

Javascript 如何将现有回调API转换为承诺?

Javascript 如何将现有回调API转换为承诺?,javascript,node.js,callback,promise,bluebird,Javascript,Node.js,Callback,Promise,Bluebird,我想使用Promissions,但我有一个回调API,其格式如下: 1.DOM加载或其他一次性事件: 2.普通回调: 3.节点样式回调节点回退: 4.具有节点样式回调的整个库: 如何在Promissions中使用API,如何承诺?Promissions具有状态,它们从挂起开始,可以解决为: 已完成意味着计算已成功完成。 拒绝表示计算失败。 承诺返回函数,它们应该返回拒绝。从承诺返回函数抛出将迫使您同时使用}catch{和.catch。使用promisified API的人不希望承诺抛出。如果您不

我想使用Promissions,但我有一个回调API,其格式如下:

1.DOM加载或其他一次性事件: 2.普通回调: 3.节点样式回调节点回退: 4.具有节点样式回调的整个库:
如何在Promissions中使用API,如何承诺?Promissions具有状态,它们从挂起开始,可以解决为:

已完成意味着计算已成功完成。 拒绝表示计算失败。 承诺返回函数,它们应该返回拒绝。从承诺返回函数抛出将迫使您同时使用}catch{和.catch。使用promisified API的人不希望承诺抛出。如果您不确定异步API在JS中如何工作,请先

1.DOM加载或其他一次性事件: 因此,创建承诺通常意味着指定它们何时结算——也就是说,当它们移动到完成或拒绝阶段时,表明数据可用,并且可以通过访问。然后

使用支持promise构造函数(如本机ES6 promises)的现代promise实现:

function load() {
    return new Promise(function(resolve, reject) {
        window.onload = resolve;
    });
}
function getUserDataAsync(userId) {
    return new Promise(function(resolve, reject) {
        getUserData(userId, resolve, reject);
    });
}
然后,您将使用这样的结果承诺:

load().then(function() {
    // Do things after onload
});
对于支持延迟的库,让我们在此示例中使用$q,但稍后我们也将使用jQuery:

function load() {
    var d = $q.defer();
    window.onload = function() { d.resolve(); };
    return d.promise;
}
或者使用类似jQuery的API,挂接发生一次的事件:

function done() {
    var d = $.Deferred();
    $("#myObject").once("click",function() {
        d.resolve();
    });
    return d.promise();
}
2.普通回调: 这些API非常常见,因为回调在JS中很常见。让我们看看onSuccess和onFail的常见情况:

使用支持promise构造函数(如本机ES6 promises)的现代promise实现:

function load() {
    return new Promise(function(resolve, reject) {
        window.onload = resolve;
    });
}
function getUserDataAsync(userId) {
    return new Promise(function(resolve, reject) {
        getUserData(userId, resolve, reject);
    });
}
对于支持延迟的库,让我们在此示例中使用jQuery,但我们也使用了上面的$q:

function getUserDataAsync(userId) {
    var d = $.Deferred();
    getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
    return d.promise();
}
jQuery还提供了一个$.Deferredfn表单,它的优点是允许我们编写一个非常接近新Promisefn表单的表达式,如下所示:

function getUserDataAsync(userId) {
    return $.Deferred(function(dfrd) {
        getUserData(userId, dfrd.resolve, dfrd.reject);
    }).promise();
}
注意:这里我们利用了一个事实,即jQuery deferred的resolve和reject方法是可分离的;即,它们绑定到jQuery.deferred的实例。并非所有lib都提供此功能

3.节点样式回调nodeback: 节点样式回调Nodeback具有特定的格式,其中回调始终是最后一个参数,其第一个参数是错误。让我们首先手动提示一个:

getStuff("dataParam", function(err, data) { …
致:

对于延迟,您可以执行以下操作:让我们在本例中使用Q,尽管Q现在支持新语法:

一般来说,您不应该过多地手动实现承诺,大多数在设计时考虑到节点以及Node 8+中的本机承诺的承诺库都有一个内置的方法来实现节点回退

var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4.具有节点样式回调的整个库: 这里没有黄金法则,你可以一个接一个地承诺。但是,一些promise实现允许你批量这样做,例如在Bluebird中,将nodeback API转换为promise API非常简单:

Promise.promisifyAll(API);
或者在节点中使用本机承诺:

注:

当然,当你在一个.then处理程序中时,你不需要承诺任何事情。从一个.then处理程序返回一个承诺。然后处理程序将用该承诺的价值来解决或拒绝。从一个.then处理程序抛出也是一个很好的实践,并且会拒绝承诺-这就是著名的承诺抛出安全。 在实际的onload情况下,应该使用addEventListener而不是onX。 我认为@Benjamin的window.onload建议不会一直有效,因为它无法检测加载后是否调用它。我已经被咬了很多次。下面是一个应该一直有效的版本:

function promiseDOMready() {
    return new Promise(function(resolve) {
        if (document.readyState === "complete") return resolve();
        document.addEventListener("DOMContentLoaded", resolve);
    });
}
promiseDOMready().then(initOnLoad);

kriskowal的Q库包含了对promise函数的回调。 这样的方法:

obj.prototype.dosomething(params, cb) {
  ...blah blah...
  cb(error, results);
}
const R =require('ramda')

/**
 * A convenient function for handle error in callback function.
 * Accept two function res(resolve) and rej(reject) ,
 * return a wrap function that accept a list arguments,
 * the first argument as error, if error is null,
 * the res function will call,else the rej function.
 * @param {function} res the function which will call when no error throw
 * @param {function} rej the function which will call when  error occur
 * @return {function} return a function that accept a list arguments,
 * the first argument as error, if error is null, the res function
 * will call,else the rej function
 **/
const checkErr = (res, rej) => (err, ...data) => R.ifElse(
    R.propEq('err', null),
    R.compose(
        res,
        R.prop('data')
    ),
    R.compose(
        rej,
        R.prop('err')
    )
)({err, data})

/**
 * wrap the callback style function to Promise style function,
 * the callback style function must restrict by convention:
 * 1. the function must put the callback function where the last of arguments,
 * such as (arg1,arg2,arg3,arg...,callback)
 * 2. the callback function must call as callback(err,arg1,arg2,arg...)
 * @param {function} fun the callback style function to transform
 * @return {function} return the new function that will return a Promise,
 * while the origin function throw a error, the Promise will be Promise.reject(error),
 * while the origin function work fine, the Promise will be Promise.resolve(args: array),
 * the args is which callback function accept
 * */
 const toPromise = (fun) => (...args) => new Promise(
    (res, rej) => R.apply(
        fun,
        R.append(
            checkErr(res, rej),
            args
        )
    )
)
可以用Q.ninvoke转换

Q.ninvoke(obj,"dosomething",params).
then(function(results) {
});

您可以将JavaScript本机承诺与节点JS一起使用

我的云9代码链接:


如果有几个函数接受回调,并且希望它们返回承诺,则可以使用此函数进行转换

function callbackToPromise(func){

    return function(){

        // change this to use what ever promise lib you are using
        // In this case i'm using angular $q that I exposed on a util module

        var defered = util.$q.defer();

        var cb = (val) => {
            defered.resolve(val);
        }

        var args = Array.prototype.slice.call(arguments);
        args.push(cb);    
        func.apply(this, args);

        return defered.promise;
    }
}

使用普通的老式javaScript,这里有一个解决方案来实现api回调

function get(url, callback) {
        var xhr = new XMLHttpRequest();
        xhr.open('get', url);
        xhr.addEventListener('readystatechange', function () {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    console.log('successful ... should call callback ... ');
                    callback(null, JSON.parse(xhr.responseText));
                } else {
                    console.log('error ... callback with error data ... ');
                    callback(xhr, null);
                }
            }
        });
        xhr.send();
    }

/**
     * @function promisify: convert api based callbacks to promises
     * @description takes in a factory function and promisifies it
     * @params {function} input function to promisify
     * @params {array} an array of inputs to the function to be promisified
     * @return {function} promisified function
     * */
    function promisify(fn) {
        return function () {
            var args = Array.prototype.slice.call(arguments);
            return new Promise(function(resolve, reject) {
                fn.apply(null, args.concat(function (err, result) {
                    if (err) reject(err);
                    else resolve(result);
                }));
            });
        }
    }

var get_promisified = promisify(get);
var promise = get_promisified('some_url');
promise.then(function (data) {
        // corresponds to the resolve function
        console.log('successful operation: ', data);
}, function (error) {
        console.log(error);
});
今天,我可以使用Node.js中的Promise作为一种简单的Javascript方法

这是一个简单而基本的承诺示例:

普通Javascript异步API代码:

function divisionAPI (number, divider, successCallback, errorCallback) {

    if (divider == 0) {
        return errorCallback( new Error("Division by zero") )
    }

    successCallback( number / divider )

}
function divisionAPI (number, divider) {

    return new Promise(function (fulfilled, rejected) {

        if (divider == 0) {
            return rejected( new Error("Division by zero") )
        }

        fulfilled( number / divider )

     })

}
Promise Javascript异步API代码:

function divisionAPI (number, divider, successCallback, errorCallback) {

    if (divider == 0) {
        return errorCallback( new Error("Division by zero") )
    }

    successCallback( number / divider )

}
function divisionAPI (number, divider) {

    return new Promise(function (fulfilled, rejected) {

        if (divider == 0) {
            return rejected( new Error("Division by zero") )
        }

        fulfilled( number / divider )

     })

}
我建议你去参观

Promise还可以与ES7中的async\wait一起使用,以使程序流等待完整的结果,如下所示:

function getName () {

    return new Promise(function (fulfilled, rejected) {

        var name = "John Doe";

        // wait 3000 milliseconds before calling fulfilled() method
        setTimeout ( 
            function() {
                fulfilled( name )
            }, 
            3000
        )

    })

}


async function foo () {

    var name = await getName(); // awaits for a fulfilled result!

    console.log(name); // the console writes "John Doe" after 3000 milliseconds

}


foo() // calling the foo() method to run the code
使用.then方法使用相同代码的另一个用法

Promise也可以在任何基于Node.js的平台上使用,比如react native

奖金:混合方法 假定回调方法有两个参数,即error和result

function divisionAPI (number, divider, callback) {

    return new Promise(function (fulfilled, rejected) {

        if (divider == 0) {
            let error = new Error("Division by zero")
            callback && callback( error )
            return rejected( error )
        }

        let result = number / divider
        callback && callback( null, result )
        fulfilled( result )

     })

}
上述方法可以响应旧式回调的结果并承诺使用

希望这有帮助。

您可以在ES6中使用本机Promise,例如处理setTimeout:

enqueue(data) {

    const queue = this;
    // returns the Promise
    return new Promise(function (resolve, reject) {
        setTimeout(()=> {
                queue.source.push(data);
                resolve(queue); //call native resolve when finish
            }
            , 10); // resolve() will be called in 10 ms
    });

}
在这个例子中,承诺没有理由失败,所以拒绝就是nev
er在节点v7.6+下调用。

,该节点具有内置承诺和异步:

// promisify.js
let promisify = fn => (...args) =>
    new Promise((resolve, reject) =>
        fn(...args, (err, result) => {
            if (err) return reject(err);
            return resolve(result);
        })
    );

module.exports = promisify;
如何使用:

let readdir = require('fs').readdir;
let promisify = require('./promisify');
let readdirP = promisify(readdir);

async function myAsyncFn(path) {
    let entries = await readdirP(path);
    return entries;
}

在Node.js 8.0.0的候选版本中,有一个新的实用程序util.promisify,它封装了promisify任何函数的功能

它与其他答案中建议的方法没有太大区别,但具有作为核心方法的优势,并且不需要额外的依赖关系

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);
然后是一个readFile方法,它返回一个本机承诺


Node.js 8.0.0包含一个新的util.promisify API,该API允许将标准Node.js回调样式API包装在一个返回承诺的函数中。下面显示了util.promisify的使用示例

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

readFile('/some/file')
  .then((data) => { /** ... **/ })
  .catch((err) => { /** ... **/ });
请参见

回调风格函数始终如此node.js中的几乎所有函数都是这种风格:

//fs.readdir(path[, options], callback)
fs.readdir('mypath',(err,files)=>console.log(files))
此样式具有相同的特征:

回调函数由最后一个参数传递

回调函数始终接受错误对象作为其第一个参数

因此,您可以编写一个函数来转换一个具有以下样式的函数:

obj.prototype.dosomething(params, cb) {
  ...blah blah...
  cb(error, results);
}
const R =require('ramda')

/**
 * A convenient function for handle error in callback function.
 * Accept two function res(resolve) and rej(reject) ,
 * return a wrap function that accept a list arguments,
 * the first argument as error, if error is null,
 * the res function will call,else the rej function.
 * @param {function} res the function which will call when no error throw
 * @param {function} rej the function which will call when  error occur
 * @return {function} return a function that accept a list arguments,
 * the first argument as error, if error is null, the res function
 * will call,else the rej function
 **/
const checkErr = (res, rej) => (err, ...data) => R.ifElse(
    R.propEq('err', null),
    R.compose(
        res,
        R.prop('data')
    ),
    R.compose(
        rej,
        R.prop('err')
    )
)({err, data})

/**
 * wrap the callback style function to Promise style function,
 * the callback style function must restrict by convention:
 * 1. the function must put the callback function where the last of arguments,
 * such as (arg1,arg2,arg3,arg...,callback)
 * 2. the callback function must call as callback(err,arg1,arg2,arg...)
 * @param {function} fun the callback style function to transform
 * @return {function} return the new function that will return a Promise,
 * while the origin function throw a error, the Promise will be Promise.reject(error),
 * while the origin function work fine, the Promise will be Promise.resolve(args: array),
 * the args is which callback function accept
 * */
 const toPromise = (fun) => (...args) => new Promise(
    (res, rej) => R.apply(
        fun,
        R.append(
            checkErr(res, rej),
            args
        )
    )
)
为了更简洁,上面的示例使用了ramda.js。js是一个优秀的函数式编程库。在上面的代码中,我们使用了类似applylike的javascript function.prototype.apply和类似appendike的javascript function.prototype.push。 因此,我们现在可以将a回调类型的函数转换为promise类型的函数:

const {readdir} = require('fs')
const readdirP = toPromise(readdir)
readdir(Path)
    .then(
        (files) => console.log(files),
        (err) => console.log(err)
    )
toPromise和checkErr函数由库拥有,它是由ramda.jscreate提供的函数编程库fork

希望这个答案对您有用。

在Node.JS中将函数转换为promise之前

转换后

以防您需要处理多个请求

在Node.js 8中,您可以使用以下npm模块动态推荐对象方法:

它使用util.promisify和代理,使对象保持不变。回忆录也可以通过使用weakmap来完成。以下是一些例子:

对于对象:

const fs = require('fs');
const doAsync = require('doasync');

doAsync(fs).readFile('package.json', 'utf8')
  .then(result => {
    console.dir(JSON.parse(result), {colors: true});
  });
具有以下功能:

doAsync(request)('http://www.google.com')
  .then(({body}) => {
    console.log(body);
    // ...
  });
您甚至可以使用本机调用和应用来绑定某些上下文:

doAsync(myFunc).apply(context, params)
  .then(result => { /*...*/ });
es6 promisify将基于回调的函数转换为基于承诺的函数

const promisify = require('es6-promisify');

const promisedFn = promisify(callbackedFn, args);
Ref:

我的promisify版本的回调函数是p函数:

var P=函数{ var self=这个; var方法=参数[0]; var params=Array.prototype.slice.callarguments,1; 返回新的PromiseSolve,拒绝=>{ 如果方法&&typeofmethod=='function'{ 参数PushFunctionError,状态{ if!err返回resolvestate 否则返回拒绝错误; }; 方法。应用自身,参数; }否则返回新错误“不是函数”; }; } var callback=functionpar,callback{ var rnd=Math.floorMath.random*2+1; 返回RND>1? } callbackcallback,err,state=>err?console.error错误:console.logstate callbackcallback,err,state=>err?console.error错误:console.logstate callbackcallback,err,state=>err?console.error错误:console.logstate callbackcallback,err,state=>err?console.error错误:console.logstate Pcallback,promise.thenv=>console.logv.catch=>console.error Pcallback,promise.thenv=>console.logv.catch=>console.error Pcallback,promise.thenv=>console.logv.catch=>console.error
Pcallback,promise.thenv=>console.logv.catch=>console.error您可以这样做

// @flow

const toPromise = (f: (any) => void) => {
  return new Promise<any>((resolve, reject) => {
    try {
      f((result) => {
        resolve(result)
      })
    } catch (e) {
      reject(e)
    }
  })
}

export default toPromise

这已经晚了5年,但我想在这里发布我的promesify版本,它从回调API中获取函数,并将它们转化为承诺

const promesify = fn => {
  return (...params) => ({
    then: cbThen => ({
      catch: cbCatch => {
        fn(...params, cbThen, cbCatch);
      }
    })
  });
};
请在此处查看这个非常简单的版本:
下面是如何将函数回调API转换为承诺的实现

function promisify(functionToExec) {
  return function() {
    var array = Object.values(arguments);
    return new Promise((resolve, reject) => {
      array.push(resolve)
      try {
         functionToExec.apply(null, array);
      } catch (error) {
         reject(error)
      }
    })
  }
}

// USE SCENARIO

function apiFunction (path, callback) { // Not a promise
  // Logic
}

var promisedFunction = promisify(apiFunction);

promisedFunction('path').then(()=>{
  // Receive the result here (callback)
})

// Or use it with await like this
let result = await promisedFunction('path');


“未来”也许已经回答了,但我通常是这样做的: 特别是像indexedDb事件包装器这样的东西,可以简化使用

或者你可能会发现未来的这种变化更具普遍性

class PromiseEx extends Promise {
  resolve(v,...a) {
    this.settled = true; this.settledValue = v;
    return(this.resolve_(v,...a))
  }
  reject(v,...a) {
    this.settled = false; this.settledValue = v;
    return(this.reject_(v,...a))
  }
  static Future(fn,...args) {
    let r,t,ft = new PromiseEx((r_,t_) => {r=r_;t=t_})
    ft.resolve_ = r; ft.reject_ = t; fn(ft,...args);
    return(ft)
  }
}

一点,一点,这可能有用

太长,读不下去了请看本答案末尾的代码片段示例 写入/转换可调用的函数 错误、结果或新承诺。。。总体安排 promiseToCB转换并导出先前编码为返回承诺的现有函数 cbToPromise转换并导出一个现有函数,该函数以前被编码为调用最后一个参数,错误为result 如果包装函数提供多个结果,则结果将是一个结果数组 例如cbundefined,path,stat-->解析[path,stat]/cbundefined[path,stat] asPromise允许您编写一个新函数来返回承诺,但它可以以任何方式调用 asCallback允许您编写一个新函数来调用cberr、result,但它可以以任何方式调用 样本函数 每个示例取2个参数,并基于随机数解析/拒绝/错误

arg2还可用于强制通过或失败。查找-通过或-失败

包装现有函数 将函数导出为当前值或使用promiseToCBfunction myFunc{},newThis; promiseToCBfunction样本Func1Arg1,arg2{ 控制台。日志决定:,arg1,arg2; 返回新的允诺函数解析、拒绝{ const timer=setTimeoutfunction{reject[arg1,arg2,ouch].join-;},5000; setTimeoutfunction{

如果arg2.endsWith-pass | | |!arg2.endsWith-fail&&Math.randomI发布了我自己的答案,但是非常欢迎关于如何为特定库或在更多情况下执行此操作以及编辑的答案。@Bergi这是一个有趣的想法,我尝试使用两种常用方法Promise构造函数和deferred object来给出一个一般性的答案.我试着在回答中给出两个备选方案。我同意RTFMing解决了这个问题,但我们经常在这里和bug跟踪器中遇到这个问题,所以我认为一个“规范问题”已经到位-我认为RTFMing解决了JS标签中大约50%的问题:D如果你有一个有趣的见解,可以在回答或编辑中做出贡献,那么它将是v非常感谢。创建一个新的Promise是否会增加任何显著的开销?我想将我所有的同步Noje.js函数包装在Promise中,以便从我的节点应用程序中删除所有同步代码,但这是最佳实践吗?换句话说,一个接受静态参数(例如字符串)并返回计算结果的函数,我应该包装它吗在承诺中?…我在某个地方读到,你不应该在Nodejs中有任何同步代码。@RonRoyston不,用承诺包装同步调用不是一个好主意-只有可能执行I/OBenjamin的异步调用,我接受了你的编辑邀请,并在案例2中添加了一个进一步的jQuery示例。在出现之前需要同行审查ars.希望您喜欢。@Roamer-1888它被拒绝了,因为我没有及时看到并接受它。值得一提的是,我认为添加的内容虽然有用,但并不太相关。Benjamin,无论resolve和reject是否编写为可重用,我敢说我建议的编辑是相关的,因为它提供了一个jQuery格式$.Deferredfn的示例,如果只包含一个jQuery示例,那么我建议它应该是这样的形式,而不是var v= $.d推迟等。因为应该鼓励人们使用被忽略的$DeFrEffn表单,另外,在这样的回答中,它使jQuery与使用.HEH的LIBS更加相称,100%次公平我不知道JQE。ry let you do$.Deferredfn,如果您在接下来的15分钟内编辑它而不是现有的示例,我相信我可以尝试按时批准它:这是一个很好的答案。您可能希望通过提及util.promisify来更新它,Node.js将从RC 8.0.0开始添加到其核心。它的工作原理与Bluebird Prom没有太大区别ise.promisify,但它的优点是不需要额外的依赖项,以防你只需要原生承诺。我已经为任何想要更多阅读该主题的人写了一篇博文。规范的答案已经提到了Q.Denodesify。我们需要强调库助手吗?我发现这对于谷歌在Q leads中承诺很有用已经完成的分支不应该使用setTimeoutresolve、0或setImmediate(如果可用)来确保异步调用它吗?@Alnitak同步调用resolve是可以的。承诺的处理程序则是,不管resolve是否同步调用。嘿,我在2014年执行此任务时曾两次建议util.promisifyion是在几个月前写的,我作为Node的核心成员推动了它,这是Node中的当前版本。因为它还没有公开发布,所以我还没有将它添加到这个答案中。不过,我们非常感谢使用反馈,并了解一些陷阱,以便为发布提供更好的文档:在ad中此外,您可能想在您的博客帖子中讨论使用util.promisify的自定义标志:@BenjaminGruenbaum您的意思是使用util.promisify.custom符号可以覆盖util.promisify的结果吗?老实说,这是故意的失误,因为我还没有找到有用的用例。也许吧你可以给我一些输入吗?当然,考虑API,比如F.S.存在或不遵循节点约定的API——一个蓝鸟的约定。允诺会使他们错,但是Upj.允诺使它们正确。已经有两个答案来描述这一点,为什么要发布一个第三个?因为这个版本的节点现在被释放了,并且我已经报告了官方的壮举。您的描述和链接。与本机promisify或以上答案相比,这有什么优势?您对本机promisify的意思是什么?当然可以:。仅举一个例子来说明基本思想。事实上,您可以看到,即使本机函数也要求函数签名必须定义为err,value=>…或者您必须定义一个cust您可以看到自定义的promisified函数。谢谢您,catcha。@loretoparisi仅供参考,var P=function fn,…args{返回新的PromiseSolve,reject=>fn.callthi
s、 …args,error,result=>error?rejecterror:resolveresult;};会做和你一样的事情,而且简单得多。这些似乎没有显示如何转换为承诺。嘿,我不确定这会给现有的答案增加什么,也许会澄清?。此外,在promise构造函数中不需要try/catch,它会自动为您执行此操作。还不清楚这对调用回调的函数起到了什么作用,而回调只有一个参数成功?错误是如何处理的?这不是承诺,它不会链接、处理回调中抛出的错误或接受回调中的第二个参数。。。
const fs = require('fs');
const doAsync = require('doasync');

doAsync(fs).readFile('package.json', 'utf8')
  .then(result => {
    console.dir(JSON.parse(result), {colors: true});
  });
doAsync(request)('http://www.google.com')
  .then(({body}) => {
    console.log(body);
    // ...
  });
doAsync(myFunc).apply(context, params)
  .then(result => { /*...*/ });
const promisify = require('es6-promisify');

const promisedFn = promisify(callbackedFn, args);
// @flow

const toPromise = (f: (any) => void) => {
  return new Promise<any>((resolve, reject) => {
    try {
      f((result) => {
        resolve(result)
      })
    } catch (e) {
      reject(e)
    }
  })
}

export default toPromise
async loadData() {
  const friends = await toPromise(FriendsManager.loadFriends)

  console.log(friends)
}
const promesify = fn => {
  return (...params) => ({
    then: cbThen => ({
      catch: cbCatch => {
        fn(...params, cbThen, cbCatch);
      }
    })
  });
};
function promisify(functionToExec) {
  return function() {
    var array = Object.values(arguments);
    return new Promise((resolve, reject) => {
      array.push(resolve)
      try {
         functionToExec.apply(null, array);
      } catch (error) {
         reject(error)
      }
    })
  }
}

// USE SCENARIO

function apiFunction (path, callback) { // Not a promise
  // Logic
}

var promisedFunction = promisify(apiFunction);

promisedFunction('path').then(()=>{
  // Receive the result here (callback)
})

// Or use it with await like this
let result = await promisedFunction('path');

// given you've defined this `Future` fn somewhere:
const Future = fn => {return new Promise((r,t) => fn(r,t))}

// define an eventFn that takes a promise `resolver`
const eventFn = resolve => {
  // do event related closure actions here. When finally done, call `resolve()`
  something.oneventfired = e => {resolve(e)}
}

// invoke eventFn in an `async` workflowFn using `Future`
// to obtain a `promise` wrapper
const workflowFn = async () => {await Future(eventFn)}
class PromiseEx extends Promise {
  resolve(v,...a) {
    this.settled = true; this.settledValue = v;
    return(this.resolve_(v,...a))
  }
  reject(v,...a) {
    this.settled = false; this.settledValue = v;
    return(this.reject_(v,...a))
  }
  static Future(fn,...args) {
    let r,t,ft = new PromiseEx((r_,t_) => {r=r_;t=t_})
    ft.resolve_ = r; ft.reject_ = t; fn(ft,...args);
    return(ft)
  }
}