在新的Promise()构造函数中使用async / await是一种反模式吗?

时间:2017-03-27 00:38:45

标签: javascript node.js asynchronous async-await

我使用async.eachLimit功能一次控制最大操作次数。

const { eachLimit } = require("async");

function myFunction() {
 return new Promise(async (resolve, reject) => {
   eachLimit((await getAsyncArray), 500, (item, callback) => {
     // do other things that use native promises.
   }, (error) => {
     if (error) return reject(error);
     // resolve here passing the next value.
   });
 });
}

正如您所看到的,我无法将myFunction函数声明为异步,因为我无法访问eachLimit函数的第二个回调中的值。< / p>

4 个答案:

答案 0 :(得分:28)

你在promise构造函数执行函数中有效地使用了promise,所以这就是Promise constructor anti-pattern

您的代码是主要风险的一个很好的例子:不安全地传播所有错误。阅读there

的原因

此外,使用async / await可以使相同的陷阱更令人惊讶。比较:

let p = new Promise(resolve => {
  ""(); // TypeError
  resolve();
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e)); // Catches it.

有一个天真的(错误的)async等价物:

let p = new Promise(async resolve => {
  ""(); // TypeError
  resolve();
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e)); // Doesn't catch it!

在浏览器的Web控制台中查找最后一个。

第一个可行,因为Promise构造函数执行函数中的任何立即异常都会方便地拒绝新构造的promise(但在你自己的任何.then内)。

第二个不起作用,因为async函数中的任何立即异常都会拒绝async函数本身返回的隐式承诺。

由于promise构造函数执行函数的返回值未使用,这是个坏消息!

您的代码

您无法将myFunction定义为async

async function myFunction() {
  let array = await getAsyncArray();
  return new Promise((resolve, reject) => {
    eachLimit(array, 500, (item, callback) => {
      // do other things that use native promises.
    }, error => {
      if (error) return reject(error);
      // resolve here passing the next value.
    });
  });
}

虽然为什么在await时使用过时的并发控制库?

答案 1 :(得分:20)

我同意上面给出的答案,但有时,在您的诺言中保持异步有时会更明智,尤其是如果您希望将多个返回诺言的操作链接在一起并避免陷入then().then()地狱的时候。我会考虑在这种情况下使用类似的方法:

const operation1 = Promise.resolve(5)
const operation2 = Promise.resolve(15)
const publishResult = () => Promise.reject(`Can't publish`)

let p = new Promise((resolve, reject) => {
  (async () => {
    try {
      const op1 = await operation1;
      const op2 = await operation2;

      if (op2 == null) {
         throw new Error('Validation error');
      }

      const res = op1 + op2;
      const result = await publishResult(res);
      resolve(result)
    } catch (err) {
      reject(err)
    }
  })()
});

(async () => {
  await p;
})().catch(e => console.log("Caught: " + e));
  1. 传递给Promise构造函数的函数不是异步的,因此linters不会显示错误。
  2. 可以使用await按顺序调用所有异步函数。
  3. 可以添加自定义错误以验证异步操作的结果
  4. 最终可以很好地捕获错误。

但是,缺点是您必须记住将try/catch放在并将其附加到reject上。

答案 2 :(得分:4)

static getPosts(){
    return new Promise( (resolve, reject) =>{
        try {
            const res =  axios.get(url);
            const data = res.data;
            resolve(
                data.map(post => ({
                    ...post,
                    createdAt: new Date(post.createdAt)
                }))
            )
        } catch (err) {
            reject(err);                
        }
    })
}

删除等待和异步将解决此问题。因为您已经应用了Promise对象,就足够了。

答案 3 :(得分:0)

相信反模式就是反模式

异步承诺回调中的抛出很容易被捕获。

(async () => {
    try {
        await new Promise (async (FULFILL, BREAK) => {
            try {
                throw null;
            }
            catch (BALL) {
                BREAK (BALL);
            }
        });
    }
    catch (BALL) {
        console.log ("(A) BALL CAUGHT", BALL);
        throw BALL;
    }
}) ().
catch (BALL => {
    console.log ("(B) BALL CAUGHT", BALL);
});

或者更简单地说,

(async () => {
    await new Promise (async (FULFILL, BREAK) => {
        try {
            throw null;
        }
        catch (BALL) {
            BREAK (BALL);
        }
    });
}) ().
catch (BALL => {
    console.log ("(B) BALL CAUGHT", BALL);
});