链接异步方法调用-javascript

链接异步方法调用-javascript,javascript,asynchronous,callback,generator,es6-promise,Javascript,Asynchronous,Callback,Generator,Es6 Promise,您有一个带有两个异步方法调用的原型对象Foo,bar和baz var bob = new Foo() Foo.prototype.bar = function land(callback) { setTimeout(function() { callback() console.log('bar'); }, 3000); }; Foo.prototype.baz = function land(callback) { setTimeout(function() {

您有一个带有两个异步方法调用的原型对象Foo,bar和baz

var bob = new Foo()

Foo.prototype.bar = function land(callback) {
  setTimeout(function() {
    callback()
    console.log('bar');
  }, 3000);
};

Foo.prototype.baz = function land(callback) {
  setTimeout(function() {
    callback()
    console.log('baz');
  }, 3000);
};
我们希望执行bob.bar().baz(),并让它按顺序记录“bar”和“baz”

如果无法修改方法调用(包括传入回调函数),如何将默认回调传入这些方法调用

一些想法:

  • 用decorator包装“bob”(对于如何实现仍然不清楚,可以使用一个小示例)

  • 修改构造函数以分配默认回调(如果未分配)(未考虑这是否可行)

  • 是否使用一个生成器包装器,该包装器将继续调用下一个方法,直到没有剩余方法为止


  • 更推荐的方法是使用,因为这是社区范围内的异步工作实践

    我们要执行bob.bar().baz(),并将其记录为“bar”和“baz” 按顺序

    为什么要这样做只是为了实现这个
    bob.bar().baz()
    “语法”?您可以非常巧妙地使用Promise API,而不需要额外的努力使语法工作,这确实会增加代码的复杂性,降低实际的可读性

    <>所以,你可能想考虑使用像这样的基于承诺的方法。它提供了比您的方法更大的灵活性:

    Foo.prototype.bar = function () {
        return new Promise(function (resolve) {
            setTimeout(function () {
                resolve()
                console.log('bar');
            }, 3000);
        };
    };
    
    Foo.prototype.baz = function () {
        return new Promise(function (resolve) {
            setTimeout(function () {
                resolve()
                console.log('baz');
            }, 3000);
        };
    };
    
    现在,您可以这样做,依次运行它们:

    var bob = new Foo();
    
    bob.bar().then(function() {
       return bob.baz();
    });
    
    // If you're using ES2015+ you could even do:
    bob.bar().then(() => bob.baz());
    
    如果您需要链接更多功能,只需执行以下操作:

    bob.bar()
        .then(() => bob.baz())
        .then(() => bob.anotherBaz())
        .then(() => bob.somethingElse());  
    

    无论如何,如果您不习惯使用承诺,那么您可能希望

    如果您希望避免回调地狱并保持理智,ES6承诺是函数式编程中最合适的方法。您只需在异步时间线中链接顺序异步任务,就像在同步时间线中工作一样

    在这种特殊情况下,您只需要说明异步函数。假设您的异步函数接受数据和回调,如
    asynch(data,myCallback)
    。让我们假设回调是错误优先类型

    例如,

    var myCallback = (error,result) => error ? doErrorAction(error)
                                             : doNormalAction(result)
    
    当您的异步函数被承诺时,实际上会返回一个函数,该函数接受您的数据并返回一个承诺。您需要在
    然后
    阶段应用
    myCallback
    。然后,
    myCallback
    的返回值将被传递到下一个阶段,在该阶段,您可以调用另一个异步函数,该函数随返回值
    myCallback
    一起提供,并且可以根据需要继续执行。那么,让我们看看我们将如何在您的工作流中实现这个抽象

    函数Foo(){}
    功能承诺(乐趣){
    返回(数据)=>新承诺((解决,拒绝)=>乐趣(数据,(错误,恢复)=>错误?拒绝(错误):解决(恢复));
    }
    函数myCallback(val){
    log(“嘿..!我有这个:”,val);
    返回val;
    }
    var bob=newfoo();
    Foo.prototype.bar=函数land(值,回调){
    setTimeout(函数(){
    callback(false,值*2);//没有返回错误,但值加倍并提供给callback
    console.log('bar');
    }, 1000);
    };
    Foo.prototype.baz=函数land(值,回调){
    setTimeout(函数(){
    callback(false,值*2);//没有返回错误,但值加倍并提供给callback
    console.log('baz');
    }, 1000);
    };
    Foo.prototype.bar=promisify(Foo.prototype.bar);
    Foo.prototype.baz=promisify(Foo.prototype.baz);
    鲍伯·巴尔(1)
    .然后(myCallback)
    .然后(鲍勃·巴兹)
    
    .然后(myCallback)
    警告这还不太正确。理想情况下,我们应该子类化Promise,并具有适当的then/catch功能,但子类化有一些注意事项。其思想是存储一个承诺生成函数的内部数组,然后当一个承诺被等待时(then/wait)串行地等待这些承诺

    const Promise = require('bluebird');
    
    class Foo {
      constructor() {
        this.queue = [];
      }
    
      // promise generating function simply returns called pGen
      pFunc(i,pGen) {
        return pGen();
      }
    
      bar() {
        const _bar = () => {
          return new Promise( (resolve,reject) => {
            setTimeout( () => {
              console.log('bar',Date.now());
              resolve();
            },Math.random()*1000);
          })      
        }
        this.queue.push(_bar);
        return this;
      }
    
      baz() {
        const _baz = () => {
          return new Promise( (resolve,reject) => {
            setTimeout( () => {
              console.log('baz',Date.now());
              resolve();
            },Math.random()*1000);
          })      
        }
        this.queue.push(_baz);
        return this;
      }
    
      then(func) {
        return Promise.reduce(this.queue, this.pFunc, 0).then(func);
      }
    }
    
    
    const foo = new Foo();
    foo.bar().baz().then( () => {
      console.log('done')
    })
    
    结果:

    messel@messels-MBP:~/Desktop/Dropbox/code/js/async-chain$ node index.js 
    bar 1492082650917
    baz 1492082651511
    done
    

    你能具体说明你将如何使用承诺吗?它们发生了,但不确定它们是如何应用于你嫁给了
    bob.bar().baz()
    语法的?有很多方法可以获得您描述的操作,但我想不出任何方法可以使用该特定语法。假设我们是:(我想我们必须把它包装起来,如果异步代码不能失败,就使用队列。如果可以,就使用承诺。看一看。不,生成器绝对帮不了你。你不允许修改调用语法。你不允许修改调用语法。感谢你用你这样做的方式解释这一点。它帮助我理解了关于t
    承诺
    。比公认的答案更好的想法,从而解决了这个问题