本文共 9592 字,大约阅读时间需要 31 分钟。
本文翻译自:
I want to work with promises but I have a callback API in a format like: 我想使用Promise,但是我有一个类似以下格式的回调API:
window.onload; // set to callback...window.onload = function() {};
function request(onChangeHandler) { ...}request(function() { // change happened ...});
function getStuff(dat, callback) { ...}getStuff("dataParam", function(err, data) { ...})
API;API.one(function(err, data) { API.two(function(err, data2) { API.three(function(err, data3) { ... }); });});
参考:
Promises have state, they start as pending and can settle to: 承诺有状态,它们从待定状态开始,可以解决:
Promise returning functions , 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 first. 如果您不确定JS中异步API的工作方式-请首先 。
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();}
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. 并非所有库都提供此功能。
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 ): 使用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); // Bluebirdvar getStuffAsync = Q.denodeify(getStuff); // Qvar getStuffAsync = util.promisify(getStuff); // Native promises, node only
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: 笔记:
.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
处理程序中抛出也是很好的做法,并且会拒绝诺言-这就是著名的诺言抛出安全性。 onload
case, you should use addEventListener
rather than onX
. 在实际的onload
情况下,应该使用addEventListener
而不是onX
。 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);
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) {});
You can use JavaScript native promises with Node JS. 您可以将JavaScript本机Promise与Node JS一起使用。
My Cloud 9 code link: 我的Cloud 9代码链接: :
/*** 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 100app.get('/listAlbums', function (req, res) { //get the post with post id 100 promisify('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().address var port = server.address().port console.log("Example app listening at http://%s:%s", host, port)})//run webservice on browser : http://localhost:8081/listAlbums
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 module var 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; }}
转载地址:http://jjcnb.baihongyu.com/