如何避免从promises中提取解析,同时在回调之前启动进程?

问题描述 投票:0回答:1

我经常发现自己使用的模式类似于:

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找到

javascript promise generator
1个回答
1
投票

你在那里的语法并没有多大意义,所以希望我能在这个答案的正确轨道上。

您还需要使用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));
© www.soinside.com 2019 - 2024. All rights reserved.