2016-08-18 35 views
11

你有一個原型對象Foo有兩個異步方法調用,bar和baz。鏈式異步方法調用 - javascript

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」。

如果您不能修改方法調用(包括傳遞迴調函數),那麼如何將默認回調傳遞給這些方法調用?

一些想法:

  1. 裹「鮑勃」與裝飾(關於如何執行仍然模糊,可以用一個小例子)

  2. 修改構造函數指定默認的回調,如果沒有指定(有沒有考慮這是否可能)

  3. 使用一個生成器包裝,將繼續調用下一個方法,直到沒有剩下?

+0

你可以指定你想使用的承諾?他們發生但不知道他們是如何應用的 –

+0

你是否結婚了'bob.bar()。baz()'語法?有很多方法可以讓你的描述得到操作,但我想不出任何可以用這種特定語法的東西。 – Mike

+0

假設我們是:(我想我們必須包裝它 –

回答

8

更推薦的方法是使用promises。因爲這是一種社區範圍內的異步事件。

我們要做bob.bar()。巴茲(),並把它記錄 「欄」 和 「巴茲」 順序。

爲什麼要這樣做只是爲了達到這個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的承諾是函數式編程的緣故最合適的方法要read this

+0

你不允許修改呼叫語法。 – Bergi

0

。您只需在異步時間線中鏈接順序異步任務,就像在同步時間線中工作一樣。

在這種特殊情況下,您只需要promisify你的異步功能。假設你的異步函數需要一個數據和一個回調,如asynch(data,myCallback)。讓我們假設回調是第一種類型的錯誤。

如;

var myCallback = (error,result) => error ? doErrorAction(error) 
             : doNormalAction(result) 

當您的異步函數被promisified時,您將實際返回一個函數,它接受您的數據並返回一個承諾。預計您將在then階段申請myCallback。然後myCallback的返回值將傳遞到下一個階段,您可以在其中調用另一個異步函數,該函數的返回值爲myCallback,並且只要您需要,這個函數就會繼續。所以讓我們看看我們如何將這個摘要應用到您的工作流程中。

function Foo(){} 
 

 
function promisify(fun){ 
 
    return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res))); 
 
} 
 

 
function myCallback(val) { 
 
    console.log("hey..! i've got this:",val); 
 
    return val; 
 
} 
 

 
var bob = new Foo(); 
 

 
Foo.prototype.bar = function land(value, callback) { 
 
    setTimeout(function() { 
 
    callback(false,value*2); // no error returned but value doubled and supplied to callback 
 
    console.log('bar'); 
 
    }, 1000); 
 
}; 
 

 
Foo.prototype.baz = function land(value, callback) { 
 
    setTimeout(function() { 
 
    callback(false,value*2); // no error returned but value doubled and supplied to callback 
 
    console.log('baz'); 
 
    }, 1000); 
 
}; 
 

 
Foo.prototype.bar = promisify(Foo.prototype.bar); 
 
Foo.prototype.baz = promisify(Foo.prototype.baz); 
 

 
bob.bar(1) 
 
    .then(myCallback) 
 
    .then(bob.baz) 
 
    .then(myCallback)

+0

你是不允許的修改調用語法。 – Bergi

0

警告這是不完全正確呢。理想情況下,我們將子類Promise和具有適當的then/catch功能,但有一些注意事項,子類bluebird Promise。這個想法是存儲一個內部承諾生成函數的數組,然後當一個承諾等待(然後/等待)連續等待這些承諾。

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

結果:

[email protected]:~/Desktop/Dropbox/code/js/async-chain$ node index.js 
bar 1492082650917 
baz 1492082651511 
done