你有一个原型对象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”。
如果你不能修改方法调用(包括传入你的回调函数),你如何将默认回调传递给这些方法调用?
一些想法:
用装饰器包裹“bob”(仍然模糊如何实现,可以用一个小例子)
修改构造函数以指定默认回调(如果没有分配)(未考虑是否可行)
使用生成器包装器继续调用next方法,直到没有剩下?
答案 0 :(得分:8)
更推荐的方法是使用promises。因为这是社区范围内做异步事物的趋势。
我们想做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());
无论如何,如果您不习惯使用承诺,可能需要read this
答案 1 :(得分:4)
警告这还不是很正确。理想情况下,我们是Promise的子类,并且具有正确的then / catch功能,但是有一些关于子类bluebird Promise的警告。我们的想法是存储一个内部数组的promise生成函数,然后等待一个Promise(然后/等待)连续等待这些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')
})
结果:
messel@messels-MBP:~/Desktop/Dropbox/code/js/async-chain$ node index.js
bar 1492082650917
baz 1492082651511
done
答案 2 :(得分:0)
如果你想避免回调地狱并保持理智,ES6承诺是最适合功能编程的方法。您只需在异步时间轴中链接顺序异步任务,就像在同步时间轴中工作一样。
在这种特殊情况下,您只需要宣传您的异步函数。假设您的异步函数接受数据和回调,如asynch(data,myCallback)
。我们假设回调是第一个错误类型。
如;
var myCallback = (error,result) => error ? doErrorAction(error)
: doNormalAction(result)
当你的异步函数被启用时,你实际上会返回一个获取数据并返回一个promise的函数。您需要在myCallback
阶段申请then
。然后,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)