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

1.DOM加载或其他一次性事件:

window.onload; // set to callback
...
window.onload = function() {

};

2.普通回调:

function request(onChangeHandler) {
    ...
}
request(function() {
    // change happened
    ...
});

3.节点样式回调(“nodeback”):

function getStuff(dat, callback) {
    ...
}
getStuff("dataParam", function(err, data) {
    ...
})

4.具有节点样式回调的整个库:

API;
API.one(function(err, data) {
    API.two(function(err, data2) {
        API.three(function(err, data3) {
            ...
        });
    });
});

我如何在promise中使用API,如何“promise”它?


当前回答

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

var P=函数(){var self=this;var方法=参数[0];var params=数组.原型.切片.调用(参数,1);return new Promise((resolve,reject)=>{if(method&&typeof(method)==“函数”){params.push(函数(错误,状态){if(!err)返回解析(状态)否则返回拒绝(err);});方法.应用(self,params);}否则返回拒绝(新错误(“不是函数”));});}var callback=函数(par,回调){var rnd=数学地板(Math.random()*2)+1;返回rnd>1?callback(null,par):回调(new Error(“trap”));}callback(“callback”,(err,state)=>错误?console.error(错误):console.log(状态))callback(“callback”,(err,state)=>错误?console.error(错误):console.log(状态))callback(“callback”,(err,state)=>错误?console.error(错误):console.log(状态))callback(“callback”,(err,state)=>错误?console.error(错误):console.log(状态))P(回调,“promise”).then(v=>console.log(v)).catch(e=>console.error(e))P(回调,“promise”).then(v=>console.log(v)).catch(e=>console.error(e))P(回调,“promise”).then(v=>console.log(v)).catch(e=>console.error(e))P(回调,“promise”).then(v=>console.log(v)).catch(e=>console.error(e))

P函数要求回调签名必须是回调(error,result)。

其他回答

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

obj.prototype.dosomething(params, cb) {
  ...blah blah...
  cb(error, results);
}

可以使用Q.invoke进行转换

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

也许已经回答了,但我通常是这样做的:

// 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)}

特别是对于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)
  }
}

死灵一点,这个链接可能有用。。。。


太长,读不下去了看看这个答案末尾的代码片段示例


编写/转换可调用的函数

cb(错误,结果)或新Promise(…)格式


promiseToCB转换并导出先前编码为返回promise的现有函数cbToPromise转换并导出一个先前编码为调用最后一个参数的现有函数(error,result)如果包装函数提供了多个结果,则结果将是一个结果数组例如cb(undefined,path,stat)--->解析([path,stat])/cb(undefine,[path,stat])asPromise允许您编写一个新函数以返回promise,但它可以以任何方式调用asCallback允许您编写一个新函数来调用cb(err,result),但它可以通过任何方式调用

示例函数

每个样本取2个参数,并基于随机数解决/拒绝/错误。

arg2也可以用于强制通过或失败。(查找“-通过”或“-失败”)。

包装现有函数

将函数导出到当前的“this”(或使用promiseToCB(函数myFunc(){},newThis);)



    promiseToCB(function sampleFunc1(arg1,arg2) {
        console.log("deciding:",arg1,arg2);
        return new Promise(function(resolve,reject){
       
           const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
           
           setTimeout(function(){
               if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
    
                   console.log("complete:",arg1,arg2);
                   clearTimeout(timer);
                   resolve([arg1,arg2,"all good"].join("-"));
               }
           },2000);
        
        });
    });
    
    cbToPromise('sampleFunc2',function someOtherName(arg1,arg2,cb) {
       console.log("deciding:",arg1,arg2);
       const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
       
       setTimeout(function(){
           if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
               console.log("complete:",arg1,arg2);
               clearTimeout(timer);
               cb(undefined,[arg1,arg2,"all good"].join("-"));
           }
       },2000);
        
    },local);
    

或者编写嵌入包装器的新函数。

     function sampleFunc3(arg1,arg2) {return asPromise(arguments,function(resolve,reject){
       console.log("deciding:",arg1,arg2);
       const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
       
       setTimeout(function(){
           if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
               console.log("complete:",arg1,arg2);
               clearTimeout(timer);
               resolve([arg1,arg2,"all good"].join("-"));
           }
       },2000);
        
    });}
    
    function sampleFunc4(arg1,arg2) {return asCallback(arguments,function(cb){
       console.log("deciding:",arg1,arg2);
       const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
       
       setTimeout(function(){
           if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
               console.log("complete:",arg1,arg2);
               clearTimeout(timer);
               cb(undefined,[arg1,arg2,"all good"].join("-"));
           }
       },2000);
        
    });}

测试上述功能的scipt


    const local = {}; 
    promiseToCB(function sampleFunc1(arg1,arg2) {
        console.log("deciding:",arg1,arg2);
        return new Promise(function(resolve,reject){
       
           const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
           
           setTimeout(function(){
               if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
    
                   console.log("complete:",arg1,arg2);
                   clearTimeout(timer);
                   resolve([arg1,arg2,"all good"].join("-"));
               }
           },2000);
        
        });
    });
    
    cbToPromise('sampleFunc2',function someOtherName(arg1,arg2,cb) {
       console.log("deciding:",arg1,arg2);
       const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
       
       setTimeout(function(){
           if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
               console.log("complete:",arg1,arg2);
               clearTimeout(timer);
               cb(undefined,[arg1,arg2,"all good"].join("-"));
           }
       },2000);
        
    },local);
    
    function sampleFunc3(arg1,arg2) {return asPromise(arguments,function(resolve,reject){
       console.log("deciding:",arg1,arg2);
       const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
       
       setTimeout(function(){
           if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
               console.log("complete:",arg1,arg2);
               clearTimeout(timer);
               resolve([arg1,arg2,"all good"].join("-"));
           }
       },2000);
        
    });}
    
    function sampleFunc4(arg1,arg2) {return asCallback(arguments,function(cb){
       console.log("deciding:",arg1,arg2);
       const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
       
       setTimeout(function(){
           if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
               console.log("complete:",arg1,arg2);
               clearTimeout(timer);
               cb(undefined,[arg1,arg2,"all good"].join("-"));
           }
       },2000);
        
    });}
    
    const log=console.log.bind(console),info=console.info.bind(console),error=console.error.bind(console);
    
    sampleFunc1("sample1","promise").then (log).catch(error);
    local.sampleFunc2("sample2","promise").then (log).catch(error);
    sampleFunc3("sample3","promise").then (log).catch(error);
    sampleFunc4("sample4","promise").then (log).catch(error);

    sampleFunc1("sample1","callback",info);
    local.sampleFunc2("sample2","callback",info);
    sampleFunc3("sample3","callback",info);
    sampleFunc4("sample4","callback",info);
    
    sampleFunc1("sample1","promise-pass").then (log).catch(error);
    local.sampleFunc2("sample2","promise-pass").then (log).catch(error);
    sampleFunc3("sample3","promise-pass").then (log).catch(error);
    sampleFunc4("sample4","promise-pass").then (log).catch(error);

    sampleFunc1("sample1","callback-pass",info);
    local.sampleFunc2("sample2","callback-pass",info);
    sampleFunc3("sample3","callback-pass",info);
    sampleFunc4("sample4","callback-pass",info);
    
    
    sampleFunc1("sample1","promise-fail").then (log).catch(error);
    local.sampleFunc2("sample2","promise-fail").then (log).catch(error);
    sampleFunc3("sample3","promise-fail").then (log).catch(error);
    sampleFunc4("sample4","promise-fail").then (log).catch(error);
    
    sampleFunc1("sample1","callback-fail",info);
    local.sampleFunc2("sample2","callback-fail",info);
    sampleFunc3("sample3","callback-fail",info);
    sampleFunc4("sample4","callback-fail",info);
 

var cpArgs=Array.prototype.slice.call.bind(Array.proto原型.slice);函数promiseToCB(nm,fn,THIS){如果(nm类型==='功能'){这=fn;fn=纳米;nm=fn.name;}此=此||此;const func=函数(){let args=cpArgs(参数);if(参数类型[args.length-1]=='函数'){const cb=args.pop();return fn.apply(THIS,args).then(函数(r){cb(未定义,r);}).捕获(cb);}其他{return fn.apply(THIS,args);}};Object.defineProperty(func,'name',{value:nm,enumerable:false,可配置:true});如果(此[nm])删除此[nm];Object.defineProperty(THIS,nm,{value:func,enumerable:false,可配置:true});返回函数;}函数cbToPromise(nm,fn,THIS){如果(nm类型==='功能'){这=fn;fn=纳米;nm=fn.name;}此=此||此;const func=函数(){let args=cpArgs(参数);if(参数类型[args.length-1]=='函数'){return fn.apply(THIS,args);}其他{return new Promise(函数(解析,拒绝){args.push(函数(错误,结果){if(error)返回reject(err);if(arguments.length==2){返回解析(result);}返回解析(cpArgs(arguments,1));});fn.apply(此,参数);});}};Object.defineProperty(func,'name',{value:nm,enumerable:false,可配置:true});如果(此[nm])删除此[nm];Object.defineProperty(THIS,nm,{value:func,enumerable:false,可配置:true});返回函数;}函数作为Promise(args,解析器,no_err){常量cb=参数[args.length-1],promise=新promise(解析器);return(cb类型=='函数')?promise.then(函数(结果){return cb(no-err,结果)}).catch(cb):promise;}函数作为回调(args,wrap,no_err){常量cb=参数[args.length-1],promise=新promise(函数解析器(resolve,reject){返回换行(函数(错误,结果){if(error)返回reject(err);解决(结果);});});return(cb类型=='函数')?promise.then(函数(结果){return cb(no-err,结果)}).catch(cb):promise;}函数cbPromiseTest(){/*全局样本Func1,样本Func2*/常量local={};promiseToCB(函数sampleFunc1(arg1,arg2){console.log(“决定:”,arg1,arg2);return new Promise(函数(解析,拒绝){const timer=setTimeout(函数(){reject([arg1,arg2,“ouch”].jjoin(“-”);},5000);setTimeout(函数){if(arg2.endsWith(“-pass”)||(!arg2.ends With(”-ffail“)&&Math.random()<0.5)){console.log(“完成:”,arg1,arg2);clearTimeout(计时器);解析([arg1,arg2,“一切正常”].join(“-”));}},2000);});});cbToPromise('sampleFunc2',函数someOtherName(arg1,arg2,cb){console.log(“决定:”,arg1,arg2);const timer=setTimeout(函数){cb([arg1,arg2,“ouch”].jjoin(“-”);},5000);setTimeout(函数){if(arg2.endsWith(“-pass”)||(!arg2.ends With(”-ffail“)&&Math.random()<0.5)){console.log(“完成:”,arg1,arg2);clearTimeout(计时器);cb(未定义,[arg1,arg2,“all good”]。join(“-”));}},2000);},本地);函数sampleFunc3(arg1,arg2){return asPromise(参数,函数(解析,拒绝){console.log(“决定:”,arg1,arg2);const timer=setTimeout(函数(){reject([arg1,arg2,“ouch”].jjoin(“-”);},5000);setTimeout(函数){if(arg2.endsWith(“-pass”)||(!arg2.ends With(”-ffail“)&&Math.random()<0.5)){console.log(“完成:”,arg1,arg2);clearTimeout(计时器);解析([arg1,arg2,“一切正常”].join(“-”));}},2000);});}函数sampleFunc4(arg1,arg2){return asCallback(参数,函数(cb){console.log(“决定:”,arg1,arg2);const timer=setTimeout(函数){cb([arg1,arg2,“ouch”].jjoin(“-”);},5000);setTimeout(函数){if(arg2.endsWith(“-pass”)||(!arg2.ends With(”-ffail“)&&Math.random()<0.5)){console.log(“完成:”,arg1,arg2);clearTimeout(计时器);cb(未定义,[arg1,arg2,“all good”]。join(“-”));}},2000);});}const log=console.log.bind(控制台),info=console.info.bind(控制台,error=console.error.bind);sampleFunc1(“sample1”,“promise”).then(log).catch(error);local.sampleFunc2(“sample2”,“promise”).then(log).catch(error);sampleFunc3(“sample3”,“promise”).then(log).catch(error);sampleFunc4(“sample4”,“promise”).then(log).catch(error);sampleFunc1(“sample1”,“回调”,信息);local.sampleFunc2(“sample2”,“回调”,信息);sampleFunc3(“sample3”,“回调”,信息);sampleFunc4(“sample4”,“回调”,信息);sampleFunc1(“sample1”,“promise pass”).then(log).catch(error);local.sampleFunc2(“sample2”,“pr”

下面是如何将函数(回调API)转换为promise的实现。

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');

在内置promise和异步的节点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;
}