【问题标题】:javascript return new Promise: short syntaxjavascript 返回新的 Promise:短语法
【发布时间】:2018-07-12 06:03:21
【问题描述】:

使用异步 javascript 时,每秒函数如下所示:

function_name()
{
    return new Promise((resolve,reject) => {
       // do some async task
       resolve();
    });
}

即使使用 es6 async/await,我也无法避免“return new Promise((resolve,reject) => { ...”部分。

有没有其他方法可以编写这样的代码而不需要所有这些重复的行?

谢谢。

【问题讨论】:

  • 你可以使用 rxjx reactivex.io/rxjs observable 和 typescript
  • @Points: 你应该怎么写下面这个简单的函数 test() { return new Promise((resolve,reject) => { setTimeout(() => { resolve(42); }); }); } 与异步/等待?那是不可能的。
  • 这在很大程度上取决于“做一些异步任务”是什么——请发布您的真实代码。您是否在任何地方都使用Promise constructor antipattern
  • @DavidVielhuber 不,确实不可能以不同的方式编写 test 示例,但是您需要这个函数来保证整个过程中仅 once 超时应用。不是每隔一种方法。
  • @DavidVielhuber 好吧,我认为该评论并不准确,因为最终 something 将不得不显式实例化 Promise。

标签: javascript es6-promise


【解决方案1】:

首先,您应该避免使用 promise anti-pattern 将新的 Promise 包装在已经返回 Promise 的其他函数周围。如果您正在这样做,那么您可以完全停止这样做,并返回已经由您的异步操作创建的承诺。这将立即简化事情。

如果您有未承诺的旧式基于回调的操作,那么一般情况下,您应该只承诺一次基本异步函数,然后仅使用返回承诺的函数版本进行编码。然后,您的所有逻辑流程都使用了 Promise,您不会在代码的常规流程中看到 new Promise(...) 样板。

此外,这些天您通常可以避免手动承诺。如果您使用的是 node.js,那么 util.promisify() 可用于创建遵循 node.js 调用约定的任何异步函数的承诺版本。

或者,如果您使用 Bluebird 承诺库,您可以使用 Promise.promisify() 承诺单个函数,也可以使用 Promise.promisifyAll() 承诺整个接口。

使用这些替代方法中的任何一种都可以避免您看到反对的样板。

但是,如果您要自己从头开始手动承诺每个函数并且不使用任何其他辅助函数,那么就无法避免 new Promise(...) 语法。这就是它所需要的。


因此,您的大部分编码不应涉及new Promise(...)。如果是这样,那么您需要向我们展示您的一些示例,我们可以建议更好/不同的编码方式。

【讨论】:

  • 在返回现有承诺时链接 then 并捕获函数是一种好习惯吗? function test() { return someAsyncTaskThatReturnsAPromise().then((result) => { return result.field; }).catch((error) => { return null; }); }
  • @DavidVielhuber - 链接.then() 是完全正常的,原因有很多。如果你链接.catch(),你必须小心你做对了。如果你想“吃掉”错误并返回一个值,即使有错误,你当然可以这样做,但这通常不是所需的设计,因为它告诉调用代码实际上没有错误。当然,在某些情况下,您希望“处理”错误并返回非错误条件,但在出现错误时返回错误并不常见。
  • @DavidVielhuber - 显然,这完全取决于您的设计,但通常您希望错误传播(作为被拒绝的承诺返回),以便调用者知道何时有错误和没有错误。如果调用者自己是链式的,那么如果错误是被拒绝的承诺,对他们来说会容易得多,因为他们的链会自动进行错误处理。如果你改为.catch()return null,那么调用者现在必须检查null 来决定他们的链是否应该继续。如果你让它拒绝,那么调用者的错误处理会更加自动。
【解决方案2】:

正在阅读 cmets 并想澄清一下:

你应该怎么写下面这个简单的函数 test() { return new Promise((resolve,reject) => { setTimeout(() => { resolve(42); }); }); }

这看起来像是一个立即解析为 42 的承诺,因此您可以:

const test = _=>Promise.resole(42);

如果您想要一个在特定时间解析并多次使用它的承诺,您可以编写以下内容:

const later = time => value =>
  new Promise(
    (resolve,reject)=>
      _=>resolve(value),
      time
  );
const afterOneSecond = later(1000);
afterOneSecond("resolves after one second");

如果您想稍后拒绝:

later(1000)(Promise.reject("rejects after one second"));

如果您使用真正的 Promise 而不是模拟的 Promise 进行测试,并且需要在没有控制台警告您的情况下传递被拒绝的 Promise 并遇到“未捕获”断点,您可以这样做:

const p = Promise.reject("rejects after one second");
p.catch(ignore=>ignore);//catch it
later(1000)(p);//pass promise without catch to later

如果你有一个函数可以返回一个承诺并处理你可以做的值。

myFunction()
.then(
  something=>something.data
)
.then(
  data=>...
)

如果你想检查 something.data 是否不为空,如果你想拒绝,你可以这样做:

myFunction()
.then(
  something=>
    (something&&something.data.length!==0)
      ? something.data
      : Promise.reject("Data cannot be empty")
)
.then(
  data=>...
)
.catch(
  e=>
    (e==="Data cannot be empty")
      ? "do something special"
      : Promse.reject(e)//keep rejecting, other error
);

如果您有一个可以抛出的同步函数,它是您的 Promise 链中的第一个函数,并且您希望它抛出的内容最终成为被拒绝的 Promise,您可以执行以下操作:

const syncFunctionThatThrows = arg => {
  if(arg===1){
    throw "arg cannot be 1";
  }
  return arg;
};

//starting promise chain with synchronous function that can throw
//  if it throws the error is absorbed by the chain and produces
//  a rejected promise
Promise.resolve(1)//going to pass 1 to syncFunctionThatThrows
.then(syncFunctionThatThrows);

要使用回调 API 作为 Promise,您可以这样做:

const asPromise = object => fn => args =>
  new Promise(
    (resolve,reject)=>
      fn.apply(
        object,
        args.concat([
          (...result)=>
            (result[0])//first argument of callback is error
              ? reject(result[0])//reject with error
              : resolve(result.slice(1,result.length))//resolve with result(s)
        ])
      )
  );

const callbackApiObjectAsPromise = asPromis(callbackApi);
callbackApiObjectAsPromise(callbackApi.someMethod)(["arg1","arg2"])
.then(
  result=>...
)
//example of mysqljs
const connectionAsPromise =  asPromise(connection);
connectionAsPromise(connection.query)([
  'SELECT * FROM `books` WHERE `author` = ?',
  ['David']
]).then(
  ([results, fields])=>...
);

如果您不喜欢DIY,可以按照Pointy 的建议使用promisifyAllpromisify

【讨论】:

    【解决方案3】:

    这可能是旧的,但我会提出我的答案,因为它可能会帮助一些迷失的灵魂。 首先你需要定义全局函数(我使用 globals.for nodejs,可以设置为任何全局对象,如 window.for browser)

    global.res= function (v){
        return new Promise(function(r){r(v);});
    }
    global.rej= function (v){
        return new Promise(function(r,rr){rr(v);});
    }
    

    然后你可以像这样在你的代码中使用 res/rej:

    async function testing(param){
        return param < 10 ? res(true) : rej(false)
    }
    
    console.log(await testing(2)) // shows 'true'
    console.log(await testing(20)) // throws error with 'false' as value
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-19
      • 2017-03-17
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-16
      相关资源
      最近更新 更多