如何避免一遍又一遍地编写“return new Promise(...)”的样板?

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

使用异步 JavaScript 时,我的代码中的每个其他函数如下所示:

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

即使使用 ES6

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

是否有另一种方法可以编写这样的代码而不需要所有这些重复的行?

javascript es6-promise
3个回答
9
投票

首先,您应该避免“promise 反模式”,它将新的 Promise 包装在已经返回 Promise 的其他函数周围。如果你这样做,那么你可以完全停止这样做,只返回异步操作已经创建的承诺。这将立即简化事情。 如果您有未承诺的旧式基于回调的操作,那么一般来说,您应该仅承诺一次基本异步函数,然后仅使用返回承诺的函数版本进行编码。然后,您的所有逻辑流程都使用 Promise,您将不会在代码的常规流程中看到

new Promise(...)

样板。

此外,现在您通常可以避免手动承诺。如果您使用的是 Node.js,那么 

util.promisify()

可用于创建遵循 Node.js 调用约定的任何异步函数的承诺版本。

或者,如果您使用 Bluebird Promise 库,您可以使用 

Promise.promisify()

承诺单个函数,也可以使用

Promise.promisifyAll()
承诺整个接口。
使用任何这些替代方法都可以避免您似乎反对的样板。

但是,如果您要自己从头开始手动 Promisify 每个函数并且不使用任何其他辅助函数,那么就无法避免

new Promise(...)

语法。这就是所需要的。


因此,您的大部分编码不应涉及
new Promise(...)

。如果是这样,那么您需要向我们展示一些示例,我们可以建议更好/不同的编码方式。

    


3
投票

你应该如何编写下面的简单函数 test() { return new Promise((resolve,reject) => { setTimeout(() => {resolve(42); }); }); }

这看起来像是一个立即解析为 42 的承诺,这样你就可以:

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

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

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"));

如果您正在使用真实的承诺而不是嘲笑的承诺进行测试,并且需要传递被拒绝的承诺,而控制台不会警告您并点击“未捕获”断点,您可以这样做:

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 作为承诺,你可以这样做:

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 的建议使用 
promisifyAll

promisify


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.