我经常发现自己使用的模式类似于:
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
,然后将其用于其他用途。更新之后,我想我会更好地了解您的需求。看起来您基本上只是在尝试将回调和Promises链接在一起。
首先,看一下正常的“回调”链接。
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库函数,我经常使用这种方法。
如果您需要一种与典型的Node格式一起使用的
promisify
来进行(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));