我想使用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,如何“promise”它?
在Node.JS中将函数转换为promise之前
var request = require('request'); //http wrapped module
function requestWrapper(url, callback) {
request.get(url, function (err, response) {
if (err) {
callback(err);
}else{
callback(null, response);
}
})
}
requestWrapper(url, function (err, response) {
console.log(err, response)
})
转换后
var request = require('request');
function requestWrapper(url) {
return new Promise(function (resolve, reject) { //returning promise
request.get(url, function (err, response) {
if (err) {
reject(err); //promise reject
}else{
resolve(response); //promise resolve
}
})
})
}
requestWrapper('http://localhost:8080/promise_request/1').then(function(response){
console.log(response) //resolve callback(success)
}).catch(function(error){
console.log(error) //reject callback(failure)
})
如果您需要处理多个请求
var allRequests = [];
allRequests.push(requestWrapper('http://localhost:8080/promise_request/1'))
allRequests.push(requestWrapper('http://localhost:8080/promise_request/2'))
allRequests.push(requestWrapper('http://localhost:8080/promise_request/5'))
Promise.all(allRequests).then(function (results) {
console.log(results);//result will be array which contains each promise response
}).catch(function (err) {
console.log(err)
});
承诺总是有决心和拒绝。当您编写异步包装器时,只需调用resolve即可。
您可以为几乎所有接受回调的函数编写包装函数,如下所示:
const myAsyncWrapper = (...params) =>
new Promise((resolve, reject) =>
someFunctionWithCallback(...params, (error, response) =>
error ? reject(error) : resolve(response)
)
);
您可以进一步编写回调到promise的转换函数:
const promisify =
(functionWithCallback) =>
(...params) =>
new Promise((resolve, reject) =>
functionWithCallback(...params, (error, response) =>
error ? reject(error) : resolve(response)
)
);
当使用较旧的库或SDK时,包装函数的概念尤其有用。例如,考虑FacebookGraph API的JavaScriptSDK,它使用类似的回调结构来发出API请求。
FB.api(apiURL, options, function (request) {
if (request.error || !request) return;
// handle request
});
在现代应用程序中,使用基于承诺的API更有用。如果您只使用一个函数一次或两次,则最好单独给出响应:
// in an async function
const response = await new Promise((resolve, reject) =>
FB.api(apiURL, (res) => (res?.error ? reject(res?.error) : resolve(res)))
);
如果经常使用该函数,可以使用相同的包装器概念来编写如下函数:
const apiWrapper = (...params) =>
new Promise((resolve, reject) =>
FB.api(...params, (res) => (res?.error ? reject(res?.error) : resolve(res)))
);
虽然promisifier有时很好,但它们不适用于这样的特定实例。在这种情况下,在Github上寻找一个现代的包装器,或者像这样编写自己的包装器。
在Node.js 8中,您可以使用此npm模块动态地promisify对象方法:
https://www.npmjs.com/package/doasync
它使用util.provify和代理,使对象保持不变。Memoization也使用WeakMaps完成)。以下是一些示例:
使用对象:
const fs = require('fs');
const doAsync = require('doasync');
doAsync(fs).readFile('package.json', 'utf8')
.then(result => {
console.dir(JSON.parse(result), {colors: true});
});
具有以下功能:
doAsync(request)('http://www.google.com')
.then(({body}) => {
console.log(body);
// ...
});
您甚至可以使用本机调用和应用来绑定某些上下文:
doAsync(myFunc).apply(context, params)
.then(result => { /*...*/ });