如何将现有回调 API 转换为 Promise?
我想使用 Promise,但我有一个回调 API,其格式如下:
###1。 DOM 加载或其他一次性事件:
window.onload; // set to callback
...
window.onload = function() {
};
###2。普通回调:
function request(onChangeHandler) {
...
}
request(function() {
// change happened
...
});
###3。节点样式回调(“nodeback”):
function getStuff(dat, callback) {
...
}
getStuff("dataParam", function(err, data) {
...
})
###4。具有节点样式回调的整个库:
API;
API.one(function(err, data) {
API.two(function(err, data2) {
API.three(function(err, data3) {
...
});
});
});
如何在 Promise 中使用 API,如何“Promisify”它们?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(24)
当您有一些需要回调的函数并且您希望它们返回承诺时,您可以使用此函数来进行转换。
When you have a few functions that take a callback and you want them to return a promise instead you can use this function to do the conversion.
在内置了 Promise 和 async 的 Node v7.6+ 下:
如何使用:
Under node v7.6+ which has built in promises and async:
How to use:
在 Node.js 8 中,您可以使用此 npm 模块即时实现对象方法:
https://www.npmjs.com/package/doasync
它使用 util.promisify 和 代理,以便您的对象保持不变不变。 记忆化也是通过使用 WeakMap 来完成的。以下是一些示例:
使用对象:
使用函数:
您甚至可以使用本机
call
和apply
来绑定某些上下文:In Node.js 8 you can promisify object methods on the fly using this npm module:
https://www.npmjs.com/package/doasync
It uses util.promisify and Proxies so that your objects stay unchanged. Memoization is also done with the use of WeakMaps). Here are some examples:
With objects:
With functions:
You can even use native
call
andapply
to bind some context:您可以在 ES6 中使用原生 Promise,例如处理 setTimeout:
在这个示例中,Promise 没有理由失败,因此永远不会调用
reject()
。You can use native Promise in ES6, for exemple dealing with setTimeout:
In this exemple, the Promise has no reason to fail, so
reject()
is never called.es6-promisify
将基于回调的函数转换为基于 Promise 的函数。参考: https://www.npmjs.com/package/es6-promisify
es6-promisify
converts callback-based functions to Promise-based functions.Ref: https://www.npmjs.com/package/es6-promisify
你可以做这样的事情
然后使用它
You can do something like this
Then use it
回调风格函数总是这样的(几乎node.js中的所有函数都是这种风格):
这种风格有相同的特点:
回调函数由最后一个参数传递。
回调函数始终接受错误对象作为其第一个参数。
因此,您可以编写一个函数来转换具有这种风格的函数,如下所示:
为了更简洁,上面的示例使用了 ramda.js。 Ramda.js 是一个优秀的函数式编程库。在上面的代码中,我们使用了它的 apply (如 javascript
function.prototype.apply
)和追加(如 javascriptfunction.prototype.push
)。因此,我们现在可以将回调样式函数转换为 Promise 样式函数:
toPromise 和 checkErr 函数由 berserk 库,它是 ramda.js 的一个函数式编程库 fork(由我创建)。
希望这个答案对您有用。
The callback style function always like this(almost all function in node.js is this style):
This style has same feature:
the callback function is passed by last argument.
the callback function always accept the error object as it's first argument.
So, you could write a function for convert a function with this style like this:
For more concise, above example used ramda.js. Ramda.js is a excellent library for functional programming. In above code, we used it's apply(like javascript
function.prototype.apply
) and append(like javascriptfunction.prototype.push
).So, we could convert the a callback style function to promise style function now:
toPromise and checkErr function is own by berserk library, it's a functional programming library fork by ramda.js(create by me).
Hope this answer is useful for you.
我的
callback
函数的 promisify 版本是P
函数:P
函数要求回调签名必须为callback(error,result)
。My promisify version of a
callback
function is theP
function:The
P
function requires that the callback signature must becallback(error,result)
.下面是如何将函数(回调 API)转换为 Promise 的实现。
Below is the implementation of how a function (callback API) can be converted to a promise.
Promise 总是有一个
resolve
和一个reject
。当您编写异步包装器时,只需调用解析即可。您可以为几乎任何接受回调的函数编写包装函数,如下所示:
您可以进一步编写回调到 Promise 的转换函数:
这种包装函数的概念在使用较旧的库或 SDK 时特别有用。例如,考虑 Facebook Graph API 的 JavaScript SDK,它使用类似的回调结构来发出 API 请求。
在现代应用程序中,使用基于 Promise 的 API 更加有用。
如果您只使用一个函数一次或两次,那么单独 Promisify 响应可能会更好:
如果您经常使用该函数,您可以使用相同的包装器概念来编写函数,如下所示:
虽然 Promisifiers 有时很棒,但它们赢了不适用于像这样的特定情况。在这样的时候,请在 Github 上查找现代包装器,或者像这样编写自己的包装器。
Promises always have a
resolve
and areject
. When you write an async wrapper, just call the resolve and there you go.You can write a wrapper function for pretty much any function taking a callback like so:
You can take this further to write a conversion function of callbacks to promises:
This concept of wrapper functions is especially useful when using older libraries or SDKs. For example, consider the Facebook Graph API's JavaScript SDK, which uses a similar callback structure for making API requests.
In modern applications, it is much more useful to use a promise-based API.
If you use a function only once or twice, it may be better to promisify the response individually:
If you use the function a lot, you can use the same wrapper concept to write a function like so:
Although promisifiers are great sometimes, they won't work for specific instances like this. In times like these, look on Github for a modern wrapper, or write your own like this.
也许已经回答了,但这就是我通常的做法:
或者您可能会发现
Future
的这种变体具有更通用的用途Perhaps already answered, but this is how I do it typically:
Or you might find this variation of
Future
to be more general purpose死灵魔法一点,这个链接可能有用......
TLDR;查看此答案末尾的代码片段示例
写入/转换函数,可以调用该函数,期望使用
cb(error,result)
或new Promise (...)
格式promiseToCB
转换并导出先前编码为返回 Promise 的现有函数cbToPromise
转换并导出先前编码为调用最后一个参数的现有函数(错误,结果)cb(未定义,路径,stat)
--->resolve([path,stat])
/cb(undefined,[path,stat])
asPromise
允许您编写一个新函数来返回Promise,但可以以任何方式调用asCallback
让您编写一个新函数来调用cb(err,result)
,但可以以任何方式调用它示例函数
每个示例需要 2 个参数,并且根据随机数解决/拒绝/错误。
arg2 也可用于强制通过或失败。 (查找“-pass”或“-fail”)。
包装现有函数
或编写嵌入包装器的新函数。
测试上述功能的脚本
Necromancing a little, bit this link may be useful....
TLDR; look at the snippet example at the end of this answer
write/convert functions that can be called expecting
a
cb(error,result)
ornew Promise (...)
formatpromiseToCB
converts and exports an existing function that's been previously coded to return a promisecbToPromise
converts and exports an existing function that's been previously coded to call the last argument with (error,result)cb(undefined,path,stat)
--->resolve([path,stat])
/cb(undefined,[path,stat])
asPromise
lets you code a new function to return a promise, but it can be called either wayasCallback
lets you code a new function to callcb(err,result)
, but it can be invoked either waysample functions
each sample takes 2 arguments, and resolves/rejects/errors based on random number.
arg2 can be also be used to force pass or fail. (looks for "-pass" or "-fail").
wrap existing functions
promiseToCB(function myFunc(){},newThis);
)or code new functions, which embed a wrapper.
test scipt for above functions
因为我们事先知道基于回调的函数的特征,
我们可以创建一个函数来转换基于回调的函数
转换为返回 Promise 的等效函数。
回调是函数的最后一个参数
如果出现错误,它始终是传递给回调的第一个参数
任何返回值都会在错误之后传递给回调
since we know the characteristics of a callback-based function in advance,
we can create a function that transforms a callback-based function
into an equivalent function returning a Promise.
The callback is the last argument of the function
If there is an error, it always the first argument passed to the callback
Any return value is passed after the error to the callback
好像晚了 5 年,但我想在这里发布我的 promesify 版本,它从回调 API 中获取函数并将它们转换为承诺,
在这里看看这个非常简单的版本:
https://gist.github.com/jdtorregrosas/aeee96dd07558a5d18db1ff02f31e21a
It is like 5 years late, but I wanted to post here my promesify version which takes functions from callbacks API and turns them into promises
Take a look to this very simple version here:
https://gist.github.com/jdtorregrosas/aeee96dd07558a5d18db1ff02f31e21a
Promise 有状态,它们开始时处于待处理状态,并且可以达到:
Promise 返回函数永远不应该抛出,它们应该返回拒绝。从承诺返回函数中抛出将迫使您同时使用
} catch {
和.catch
。使用 Promisified API 的人并不期望 Promise 会抛出异常。如果您不确定异步 API 在 JS 中的工作原理 - 请先看看这个答案。1. DOM 加载或其他一次性事件:
因此,创建 Promise 通常意味着指定它们何时解决 - 这意味着它们何时移至已完成或拒绝阶段以指示数据可用(并且可以使用
.then< /代码>)。
使用像原生 ES6 Promise 一样支持
Promise
构造函数的现代 Promise 实现:然后,您可以像这样使用生成的 Promise:
使用支持 deferred 的库(我们在此示例中使用 $q,但我们将稍后也使用 jQuery):
或者使用类似 jQuery 的 API,挂钩发生一次的事件:
2. 普通回调:
这些 API 相当常见,因为……回调在 JS 中很常见。让我们看一下具有
onSuccess
和onFail
的常见情况:使用支持
Promise
构造函数(如原生 ES6 Promise)的现代 Promise 实现:使用支持以下功能的库:支持 deferred (这里我们使用 jQuery 来做这个例子,但上面我们也使用了 $q):
jQuery 还提供了一个
$.Deferred(fn)
形式,它的优点是允许我们编写一个非常接近地模拟new Promise(fn)
形式的表达式,如下所示:注意:这里我们利用了 jQuery 延迟的
resolve
和reject
方法是“可分离的”; IE。它们绑定到 jQuery.Deferred() 的实例。并非所有库都提供此功能。3. 节点样式回调(“nodeback”):
节点样式回调(nodebacks)具有特定的格式,其中回调始终是最后一个参数,而其第一个参数是错误。让我们首先手动承诺一个:
到:
使用 deferreds,您可以执行以下操作(在本例中我们使用 Q,尽管 Q 现在支持新语法 你应该更喜欢哪个):
一般来说,你不应该过多地手动进行 Promise,大多数以 Node 为设计理念的 Promise 库以及 Node 8+ 中的原生 Promise 都有一个内置的承诺节点备份的方法。例如
4. 具有节点样式回调的整个库:
这里没有黄金法则,您可以一一承诺它们。但是,某些 Promise 实现允许您批量执行此操作,例如在 Bluebird 中,将 Nodeback API 转换为 Promise API 非常简单:
或者使用 Node原生 Promise >:
注意:
.then
处理程序中时,你不需要承诺事情。从.then
处理程序返回一个 Promise 将使用该 Promise 的值来解析或拒绝。从.then
处理程序抛出也是一种很好的做法,并且会拒绝 Promise - 这就是著名的 Promise 抛出安全性。onload
情况下,您应该使用addEventListener
而不是onX
。Promises have state, they start as pending and can settle to:
Promise returning functions should never throw, they should return rejections instead. Throwing from a promise returning function will force you to use both a
} catch {
and a.catch
. People using promisified APIs do not expect promises to throw. If you're not sure how async APIs work in JS - please see this answer first.1. DOM load or other one time event:
So, creating promises generally means specifying when they settle - that means when they move to the fulfilled or rejected phase to indicate the data is available (and can be accessed with
.then
).With modern promise implementations that support the
Promise
constructor like native ES6 promises:You would then use the resulting promise like so:
With libraries that support deferred (Let's use $q for this example here, but we'll also use jQuery later):
Or with a jQuery like API, hooking on an event happening once:
2. Plain callback:
These APIs are rather common since well… callbacks are common in JS. Let's look at the common case of having
onSuccess
andonFail
:With modern promise implementations that support the
Promise
constructor like native ES6 promises:With libraries that support deferred (Let's use jQuery for this example here, but we've also used $q above):
jQuery also offers a
$.Deferred(fn)
form, which has the advantage of allowing us to write an expression that emulates very closely thenew Promise(fn)
form, as follows:Note: Here we exploit the fact that a jQuery deferred's
resolve
andreject
methods are "detachable"; ie. they are bound to the instance of a jQuery.Deferred(). Not all libs offer this feature.3. Node style callback ("nodeback"):
Node style callbacks (nodebacks) have a particular format where the callbacks is always the last argument and its first parameter is an error. Let's first promisify one manually:
To:
With deferreds you can do the following (let's use Q for this example, although Q now supports the new syntax which you should prefer):
In general, you should not promisify things manually too much, most promise libraries that were designed with Node in mind as well as native promises in Node 8+ have a built in method for promisifying nodebacks. For example
4. A whole library with node style callbacks:
There is no golden rule here, you promisify them one by one. However, some promise implementations allow you to do this in bulk, for example in Bluebird, converting a nodeback API to a promise API is as simple as:
Or with native promises in Node:
Notes:
.then
handler you do not need to promisify things. Returning a promise from a.then
handler will resolve or reject with that promise's value. Throwing from a.then
handler is also good practice and will reject the promise - this is the famous promise throw safety.onload
case, you should useaddEventListener
rather thanonX
.今天,我可以在
Node.js
中使用Promise
作为简单的 Javascript 方法。Promise
的简单基本示例(使用 KISS< /strong> 方式):Plain Javascript Async API 代码:
Promise
Javascript Async API 代码:(我建议访问 这个漂亮的源代码)
此外
Promise
可以与async\ 一起使用在
,使程序流等待ES7
中等待fullfiled
结果,如下所示:使用
.then() 来使用相同代码的另一种用法方法
Promise
还可以在任何基于 Node.js 的平台上使用,例如react-native
。奖励:混合方法
(假设回调方法有两个参数:错误和结果)
上述方法可以响应老式回调和 Promise 用法的结果。
希望这有帮助。
Today, I can use
Promise
inNode.js
as a plain Javascript method.A simple and basic example to
Promise
(with KISS way):Plain Javascript Async API code:
Promise
Javascript Async API code:(I recommend visiting this beautiful source)
Also
Promise
can be used with togetherasync\await
inES7
to make the program flow wait for afullfiled
result like the following:Another usage with the same code by using
.then()
methodPromise
can also be used on any platform that is based on Node.js likereact-native
.Bonus: An hybrid method
(The callback method is assumed to have two parameters as error and result)
The above method can respond result for old fashion callback and Promise usages.
Hope this helps.
在 Node.JS 中将函数转换为 Promise 之前
转换之后
如果您需要处理多个请求
Before converting a function as promise In Node.JS
After Converting It
Incase you need to handle multiple request
Node.js 8.0.0 包含一个新的
util.promisify()
< /a> API,允许将标准 Node.js 回调样式 API 包装在返回 Promise 的函数中。下面显示了util.promisify()
的使用示例。请参阅改进对 Promise 的支持
Node.js 8.0.0 includes a new
util.promisify()
API that allows standard Node.js callback style APIs to be wrapped in a function that returns a Promise. An example use ofutil.promisify()
is shown below.See Improved support for Promises
我认为 @Benjamin 的 window.onload 建议不会一直有效,因为它不会检测加载后是否调用它。我已经被咬过很多次了。这是一个应该始终有效的版本:
I don't think the
window.onload
suggestion by @Benjamin will work all the time, as it doesn't detect whether it is called after the load. I have been bitten by that many times. Here is a version which should always work:我通常使用的简单通用函数。
如何使用它
promisify
接受带有回调的函数:您可能不是在寻找这个答案,但这将有助于理解可用 utils 的内部工作原理
A simple generic function I normally use.
How to use it
promisify
accepts a function with a callback:You are probably not looking for this answer, but this will help understand the inner workings of the available utils
在 Node.js 8.0.0 的候选版本中,有一个新的实用程序 util.promisify(我已经写过关于 util.promisify),封装了承诺任何功能的能力。
它与其他答案中建议的方法没有太大区别,但具有作为核心方法的优点,并且不需要额外的依赖项。
然后,您有一个返回本机
Promise
的readFile
方法。In release candidate for Node.js 8.0.0, there's a new utility,
util.promisify
(I've written about util.promisify), that encapsulates the capacity of promisifying whatever function.It is not much different from the approaches suggested in the other answers, but has the advantage of being a core method, and not requiring additional dependencies.
Then you've a
readFile
method that returns a nativePromise
.您可以将 JavaScript 原生 Promise 与 Node JS 结合使用。
My Cloud 9 代码链接:https://ide.c9.io/adx2803/native -节点中的承诺
You can use JavaScript native promises with Node JS.
My Cloud 9 code link: https://ide.c9.io/adx2803/native-promises-in-node
使用普通的旧式 JavaScript,这里有一个承诺 api 回调的解决方案。
With plain old vanilla javaScript, here's a solution to promisify an api callback.
kriskowal 的 Q 库包含回调到 Promise 函数。
像这样的方法:
可以用Q.ninvoke转换
The Q library by kriskowal includes callback-to-promise functions.
A method like this:
can be converted with Q.ninvoke