如何将现有的回调API转换为Promise?
本文翻译自:How do I convert an existing callback API to promises?
I want to work with promises but I have a callback API in a format like: 我想使用Promise,但是我有一个类似以下格式的回调API:
1. DOM load or other one time event: 1. DOM加载或其他一次事件:
window.onload; // set to callback
...
window.onload = function() {};
2. Plain callback: 2.普通回调:
function request(onChangeHandler) {...
}
request(function() {// change happened...
});
3. Node style callback ("nodeback"): 3.节点样式回调(“ nodeback”):
function getStuff(dat, callback) {...
}
getStuff("dataParam", function(err, data) {...
})
4. A whole library with node style callbacks: 4.带有节点样式回调的整个库:
API;
API.one(function(err, data) {API.two(function(err, data2) {API.three(function(err, data3) {...});});
});
How do I work with the API in promises, how do I "promisify" it? 如何在promise中使用API,如何“承诺”它?
#1楼
参考:https://stackoom.com/question/1WUQK/如何将现有的回调API转换为Promise
#2楼
Promises have state, they start as pending and can settle to: 承诺有状态,它们从待定状态开始,可以解决:
- fulfilled meaning that the computation completed successfully. 完成意味着计算成功完成。
- rejected meaning that the computation failed. 拒绝表示计算失败。
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
. 从promise返回函数抛出将迫使您同时使用} catch {
和 .catch
。 People using promisified APIs do not expect promises to throw. 使用承诺的API的人们不会期望诺言。 If you're not sure how async APIs work in JS - please see this answer first. 如果您不确定JS中异步API的工作方式-请首先查看此答案 。
1. DOM load or other one time event: 1. DOM加载或其他一次事件:
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
). 因此,创建承诺通常意味着指定何时结算-即何时进入承诺阶段或拒绝阶段以指示数据可用(并且可以通过.then
访问)。
With modern promise implementations that support the Promise
constructor like native ES6 promises: 使用支持Promise
构造函数的现代Promise
实现(例如本机ES6 Promise
:
function load() {return new Promise(function(resolve, reject) {window.onload = resolve;});
}
You would then use the resulting promise like so: 然后,您将使用产生的承诺,如下所示:
load().then(function() {// Do things after onload
});
With libraries that support deferred (Let's use $q for this example here, but we'll also use jQuery later): 使用支持延迟的库(让我们在此示例中使用$ q,但稍后我们还将使用jQuery):
function load() {var d = $q.defer();window.onload = function() { d.resolve(); };return d.promise;
}
Or with a jQuery like API, hooking on an event happening once: 或者使用jQuery之类的jQuery,将一次事件挂起:
function done() {var d = $.Deferred();$("#myObject").once("click",function() {d.resolve();});return d.promise();
}
2. Plain callback: 2.普通回调:
These APIs are rather common since well… callbacks are common in JS. 这些API相当常见,因为……在JS中回调很常见。 Let's look at the common case of having onSuccess
and onFail
: 让我们看一下具有onSuccess
和onFail
的常见情况:
function getUserData(userId, onLoad, onFail) { …
With modern promise implementations that support the Promise
constructor like native ES6 promises: 使用支持Promise
构造函数的现代Promise
实现(例如本机ES6 Promise
:
function getUserDataAsync(userId) {return new Promise(function(resolve, reject) {getUserData(userId, resolve, reject);});
}
With libraries that support deferred (Let's use jQuery for this example here, but we've also used $q above): 使用支持延迟的库(在此示例中,我们使用jQuery,但上面我们也使用$ q):
function getUserDataAsync(userId) {var d = $.Deferred();getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });return d.promise();
}
jQuery also offers a $.Deferred(fn)
form, which has the advantage of allowing us to write an expression that emulates very closely the new Promise(fn)
form, as follows: jQuery还提供了$.Deferred(fn)
形式,它的优点是允许我们编写一个非常接近new Promise(fn)
形式的表达式,如下所示:
function getUserDataAsync(userId) {return $.Deferred(function(dfrd) {getUserData(userId, dfrd.resolve, dfrd.reject);}).promise();
}
Note: Here we exploit the fact that a jQuery deferred's resolve
and reject
methods are "detachable"; 注意:这里我们利用了一个事实,即jQuery deferred的resolve
和reject
方法是“可分离的”。 ie. 即。 they are bound to the instance of a jQuery.Deferred(). 它们绑定到jQuery.Deferred()的实例 。 Not all libs offer this feature. 并非所有库都提供此功能。
3. Node style callback ("nodeback"): 3.节点样式回调(“ nodeback”):
Node style callbacks (nodebacks) have a particular format where the callbacks is always the last argument and its first parameter is an error. 节点样式回调(nodebacks)具有特定的格式,其中回调始终是最后一个参数,而其第一个参数是错误。 Let's first promisify one manually: 让我们首先手动分配一个:
getStuff("dataParam", function(err, data) { …
To: 至:
function getStuffAsync(param) {return new Promise(function(resolve, reject) {getStuff(param, function(err, data) {if (err !== null) reject(err);else resolve(data);});});
}
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 ): 使用deferred,您可以执行以下操作(尽管本例中Q现在支持您应首选使用的新语法,但让本示例使用Q):
function getStuffAsync(param) {var d = Q.defer();getStuff(param, function(err, data) {if (err !== null) d.reject(err);else d.resolve(data);});return d.promise;
}
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. 通常,您不应该过多地手动分配内容,大多数基于Node设计的Promise库以及Node 8+中的本机Promise具有内置的用于使NodeBback富集的方法。 For example 例如
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. A whole library with node style callbacks: 4.带有节点样式回调的整个库:
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: 但是,某些promise实现允许您批量执行此操作,例如在Bluebird中,将nodeback API转换为promise API很简单:
Promise.promisifyAll(API);
Or with native promises in Node : 或在Node中具有本机承诺 :
const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)})).reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
Notes: 笔记:
- Of course, when you are in a
.then
handler you do not need to promisify things. 当然,当你在一个.then
处理你不需要promisify事情。 Returning a promise from a.then
handler will resolve or reject with that promise's value. 从.then
处理程序返回一个诺言将解决或拒绝该诺言的值。 Throwing from a.then
handler is also good practice and will reject the promise - this is the famous promise throw safety. 从.then
处理程序中抛出也是很好的做法,并且会拒绝诺言-这就是著名的诺言抛出安全性。 - In an actual
onload
case, you should useaddEventListener
rather thanonX
. 在实际的onload
情况下,应该使用addEventListener
而不是onX
。
#3楼
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. 我认为@Benjamin的window.onload
建议不会一直有效,因为它无法检测到加载后是否被调用。 I have been bitten by that many times. 我被很多次咬伤了。 Here is a version which should always work: 这是一个应该始终有效的版本:
function promiseDOMready() {return new Promise(function(resolve) {if (document.readyState === "complete") return resolve();document.addEventListener("DOMContentLoaded", resolve);});
}
promiseDOMready().then(initOnLoad);
#4楼
The Q library by kriskowal includes callback-to-promise functions. kriskowal的Q库包含应答回调函数。 A method like this: 这样的方法:
obj.prototype.dosomething(params, cb) {...blah blah...cb(error, results);
}
can be converted with Q.ninvoke 可以用Q.ninvoke转换
Q.ninvoke(obj,"dosomething",params).
then(function(results) {
});
#5楼
You can use JavaScript native promises with Node JS. 您可以将JavaScript本机Promise与Node JS一起使用。
My Cloud 9 code link: https://ide.c9.io/adx2803/native-promises-in-node 我的Cloud 9代码链接: https : //ide.c9.io/adx2803/native-promises-in-node
/**
* Created by dixit-lab on 20/6/16.
*/var express = require('express');
var request = require('request'); //Simplified HTTP request client.var app = express();function promisify(url) {return new Promise(function (resolve, reject) {request.get(url, function (error, response, body) {if (!error && response.statusCode == 200) {resolve(body);}else {reject(error);}})});
}//get all the albums of a user who have posted post 100
app.get('/listAlbums', function (req, res) {//get the post with post id 100promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {var obj = JSON.parse(result);return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums')}).catch(function (e) {console.log(e);}).then(function (result) {res.end(result);})
})var server = app.listen(8081, function () {var host = server.address().addressvar port = server.address().portconsole.log("Example app listening at http://%s:%s", host, port)
})//run webservice on browser : http://localhost:8081/listAlbums
#6楼
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时,您可以使用此函数进行转换。
function callbackToPromise(func){return function(){// change this to use what ever promise lib you are using// In this case i'm using angular $q that I exposed on a util modulevar defered = util.$q.defer();var cb = (val) => {defered.resolve(val);}var args = Array.prototype.slice.call(arguments);args.push(cb); func.apply(this, args);return defered.promise;}
}
如何将现有的回调API转换为Promise?相关推荐
- 如何将小程序内置非promise API转换为promise对象(风袖小程序的学习)
非常重要,便于项目大局观,使用es7的 async和await 如何将小程序内置非promise API转换为promise 这里是我封装的一个wx.request函数如何将wx.request转换成 ...
- 小程序API的Promise化
小程序官方提供的异步API都是基于回调函数来实现的,如大量的使用回调函数就会造成 回调地狱 的问题,同时代码的可读性和可维护性差,那么这篇内容主要来讲小程序API的Promise化,Promise是一 ...
- 微信小程序API的Promise化及全局状态管理MobX
文章目录 API的Promise化 创建promise化的对象 全局状态管理 创建 页面中绑定 页面中使用 组件中绑定 组件中使用 API的Promise化 默认情况下小程序官方提供的API都是基于回 ...
- 【JavaScript】回调地狱、Promise
文章目录 1. 回调函数 2. 异步任务 3. 回调地狱 4. Promise 4.1 Promise定义 4.2 Promise基础用法 4.2.1 生成Promise实例 4.2.2 Promis ...
- 回调地狱和Promise
目录 1.回调地狱callback-hell 由于fs.readFile是异步操作,所以你不能判断下面三个文件的执行顺序 var fs = require('fs')fs.readFile('./da ...
- SQL Server扩展事件(Extended Events)-- 将现有 SQL 跟踪脚本转换为扩展事件会话
SQL Server扩展事件(Extended Events)-- 将现有 SQL 跟踪脚本转换为扩展事件会话 如果您具有想要转换为扩展事件会话的现有 SQL 跟踪脚本,则可以使用本主题中的过程创建等 ...
- api pdo php,从PHP Mysql API转换为PDO时如何处理数据类型
我正在将我们的站点从PHP Mysql API转换为PDO,并且遇到了数据类型问题. 以前,我们对所有变量都进行了转义,就好像它们是字符串一样.例如, SET varname = '$varvalue ...
- ES6(三)——回调地狱和promise异步任务顺序执行(传参、错误处理)
文章目录 方法一.回调函数(回调地狱) 方法二:promise 2.1异步任务传参(单个) 2.2异步任务传参(多个) 2.3 错误处理 2.4 Promiss对象三大状态: (学名) 2.5 Pro ...
- 微信小程序-API的Promise化
npm初始化 npm init -y 安装小程序的Promise包 1.使用腾讯官方出的第三方库实现小程序所有API 的 Promise 化 npm install --save miniprogra ...
最新文章
- nacos 负载策略_Spring Cloud Alibaba:Nacos 作为注册中心和配置中心使用
- 手把手教你用python抢票回家过年 !(附代码)
- websocket创建失败_SpringBoot2.2 实践WebSocket被不靠谱的百度搜索结果坑了多少人
- 关联关系和依赖关系的区别
- 算法笔记_065:分治法求逆序对(Java)
- Python类方法和静态方法
- 通过图标来识别网站用户指纹
- 游戏音效的发展和制作游戏音效的意义
- CentOS下使用命令行Web浏览器Links
- 大话西游,唐僧与悟空合伙创业,股权几何?
- RuntimeError: mat1 and mat2 shapes cannot be multiplied
- 追MM“23式”—— GOF 23种设计模式
- JavaScript 数据结构与算法(队列)
- 数据结构 —— 队列、栈、链表的区别
- 【Jmeter常用断言组件】
- numpy均匀分布_Numpy的基本操作
- OpenCV将视频转存为一帧帧的图片(Python)
- java校园导航_基于Android平台的校园导航系统
- 【OpenCV】获得视频的帧数、FPS以及按帧数将图片保存到本地
- 什么是HTTP协议及工作原理
热门文章
- 再论c++模板之类型识别之如何得到类型信息
- andriod 接入mqtt_Android 连接阿里云 mqtt失败
- Swift String字符串版本更新特性
- Swift中@IBDesignable/@IBInspectable的使用
- (005) java后台开发之Mac终端命令运行java
- (0060)iOS开发之iOS 9: UIStackView入门
- android列表集合点击事件,给ListeView列表中的每一个Item添加点击事件
- uniapp启动页,底部虚拟按钮向上闪一下的问题
- 批量启动关闭MS SQL 2005服务BAT
- java开发 中台