我经常发现自己使用的模式类似于:
const foo = () => {
const _resolve;
const promise = new Promise(resolve => _resolve = resolve);
myAsyncCall(_resolve);
return (dataWeDontHaveYet) => promise.then(cb => cb(dataWeDontHaveYet));
}
const finalData = async2(foo());
function async2(cb) {
... async stuff ...
return cb(dataWeDidntHaveBefore);
}
function myAsyncCall(cb) { return cb(somePrimitive); }
所以我想要立即启动异步调用,但是我需要根据我尚未拥有的数据来解决异步调用问题。
排序就像一个队列。
也许我不应该使用承诺?我不确定。我以前用过这个,但我找不到代码。目前我正在尝试将流转换为生成器,并且我正处于艰难时期。
编辑:我创建了一个非常具体的问题的新问题,可以在How to convert a stream into a generator without leaking resolve from a promise找到
你在那里的语法并没有多大意义,所以希望我能在这个答案的正确轨道上。
您还需要使用Promise或回调等待异步数据。你只需将它们连在一起并返回Promise的开头即可。
如果myAsyncCall()
也返回Promise
,你可以这样做:
return myAsyncCall();
这将返回Promise
,一旦myAsyncCall()
完成将解决。如果您需要转换该数据,您可以将任意数量的then()
链接到它上面:
return myAsyncCall().then(d => transform(d));
这将首先解决myAsyncCall()
,然后转换,然后随后的then()
调用将获得最新的调用。
如果myAsyncCall()
使用回调代替,你可以返回一个Promise
:
return new Promise((resolve) => {
myAsyncCall(data => resolve(data));
});
这将让myAsyncCall()
解决,然后将数据传递给Promise
,然后用于进一步的事情。
更新后,我想我更了解你在寻找什么。看起来你基本上只是想把回调和Promise联系在一起。
首先,看看正常的“回调”链接。
const a = (start, cb) => cb(start);
const b = (input, cb) => cb(input + 5);
a(1, result =>
b(result, newResult =>
console.log(newResult)
)
);
这是链接的回调方式。基本上,您将函数作为参数传递,该参数接收作为前一个函数的结果的参数。
嵌套的方法有点乱,所以很多人会稍微分解一下:
const a = (start, cb) => cb(start);
const b = (input, cb) => cb(input + 5);
const onA = result => b(result, onB);
const onB = result => console.log(result);
a(1, onA);
使用Promises
,他们使用then()
链接。上面使用所有Promises看起来像这样:
const a = start => Promise.resolve(start);
const b = input => Promise.resolve(input + 5);
a(1).then(b).then(result => console.log(result));
现在,当你需要混合两者时,有几种方法。一种是以更直接的方式将它们混合在一起:
const a = start => Promise.resolve(start);
const b = (input, cb) => cb(input + 5);
a(1).then(result => b(result, result => console.log(result)));
这样可行,但会给你带来很多嵌套回调的混乱。
更简洁的方法是“宣传”回调。虽然有些库会为你做这个,但快速的promisify
函数如下所示:
const promisify = func => (...args) => new Promise(resolve => {
const cb = result => resolve(result);
func.apply(func, args.concat(cb));
});
const a = (start, cb) => cb(start);
const b = (input, cb) => cb(input + 5);
const aPromisified = promisify(a);
const bPromisified = promisify(b);
aPromisified(1)
.then(bPromisified)
.then(result => console.log(result));
基本上,它只是将回调函数包装到Promise中。然后,您可以将其视为承诺。我对内置的Node库函数使用了这种方法。
如果你需要一个promisify
,它使用典型的Node格式来回调(err, result)
,那么你可以使用这个,然后传入true
作为“withErr”:
const promisify = (func, withErr = false) => (...args) => new Promise((resolve, reject) => {
const handler = (err, result) => {
if(withErr) {
err ? reject(err) : resolve(result);
} else {
resolve(err);
}
}
func.apply(func, args.concat(handler));
});
const aCallback = (start, cb) => cb(start);
const bCallback = (input, cb) => cb(input === 3 && 'cannot be 3', input + 5);
const a = promisify(aCallback);
const b = promisify(bCallback, true);
a(1).then(b).then(r => console.log(r));
a(3).then(b).catch(err => console.error(err));