链接异步方法调用 - javascript
chaining async method calls - javascript
您有一个带有两个异步方法调用的原型对象 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"(如何实现仍然模糊,可以使用一个小例子)
如果 none 已分配,则修改构造函数以分配默认回调(尚未考虑是否可能)
使用将继续调用下一个方法直到剩下 none 的生成器包装器?
更推荐的方法是使用 promises,因为这是社区范围内进行异步工作的做法。
We want to do bob.bar().baz() and have it log "bar" and "baz"
sequentially.
你为什么要这样做只是为了实现这个bob.bar().baz()
“语法”?您可以使用 Promise API w/o 额外的努力来使语法正常工作,这确实会增加代码的复杂性,从而降低实际的可读性。
因此,您可能要考虑使用像这样的基于承诺的方法。它提供了比您的方法所能达到的更大的灵活性:
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());
无论如何,如果您不习惯使用 promise,您可能想要 read this
如果你想避免回调地狱并保持理智,ES6 承诺是函数式编程最合适的方法。您只需将异步时间线中的顺序异步任务链接起来,就像在同步时间线中工作一样。
在这种特殊情况下,您只需要承诺您的异步函数。假设您的异步函数接受一个数据和一个回调,如 asynch(data,myCallback)
。让我们假设回调是错误优先类型。
如;
var myCallback = (error,result) => error ? doErrorAction(error)
: doNormalAction(result)
当你的异步函数被 promified 时,你实际上会 returned 一个函数,它接受你的数据并且 return 是一个承诺。您需要在 then
阶段申请 myCallback
。 myCallback
的 return 值将被传递到下一阶段,您可以在该阶段调用另一个异步函数,该函数提供了 myCallback
的 return 值,并且这种情况会继续下去只要你需要。因此,让我们看看我们将如何在您的工作流中实现这个摘要。
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)
警告这还不太正确。理想情况下,我们将 Promise 子类化并具有适当的 then/catch 功能,但子类化 bluebird Promise 有一些注意事项。这个想法是存储一个承诺生成函数的内部数组,然后当一个承诺被等待时(then/await)连续地等待这些承诺。
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
您有一个带有两个异步方法调用的原型对象 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"(如何实现仍然模糊,可以使用一个小例子)
如果 none 已分配,则修改构造函数以分配默认回调(尚未考虑是否可能)
使用将继续调用下一个方法直到剩下 none 的生成器包装器?
更推荐的方法是使用 promises,因为这是社区范围内进行异步工作的做法。
We want to do bob.bar().baz() and have it log "bar" and "baz" sequentially.
你为什么要这样做只是为了实现这个bob.bar().baz()
“语法”?您可以使用 Promise API w/o 额外的努力来使语法正常工作,这确实会增加代码的复杂性,从而降低实际的可读性。
因此,您可能要考虑使用像这样的基于承诺的方法。它提供了比您的方法所能达到的更大的灵活性:
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());
无论如何,如果您不习惯使用 promise,您可能想要 read this
如果你想避免回调地狱并保持理智,ES6 承诺是函数式编程最合适的方法。您只需将异步时间线中的顺序异步任务链接起来,就像在同步时间线中工作一样。
在这种特殊情况下,您只需要承诺您的异步函数。假设您的异步函数接受一个数据和一个回调,如 asynch(data,myCallback)
。让我们假设回调是错误优先类型。
如;
var myCallback = (error,result) => error ? doErrorAction(error)
: doNormalAction(result)
当你的异步函数被 promified 时,你实际上会 returned 一个函数,它接受你的数据并且 return 是一个承诺。您需要在 then
阶段申请 myCallback
。 myCallback
的 return 值将被传递到下一阶段,您可以在该阶段调用另一个异步函数,该函数提供了 myCallback
的 return 值,并且这种情况会继续下去只要你需要。因此,让我们看看我们将如何在您的工作流中实现这个摘要。
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)
警告这还不太正确。理想情况下,我们将 Promise 子类化并具有适当的 then/catch 功能,但子类化 bluebird Promise 有一些注意事项。这个想法是存储一个承诺生成函数的内部数组,然后当一个承诺被等待时(then/await)连续地等待这些承诺。
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