我想使用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”它?
使用普通的javaScript,这里有一个承诺api回调的解决方案。
function get(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('get', url);
xhr.addEventListener('readystatechange', function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log('successful ... should call callback ... ');
callback(null, JSON.parse(xhr.responseText));
} else {
console.log('error ... callback with error data ... ');
callback(xhr, null);
}
}
});
xhr.send();
}
/**
* @function promisify: convert api based callbacks to promises
* @description takes in a factory function and promisifies it
* @params {function} input function to promisify
* @params {array} an array of inputs to the function to be promisified
* @return {function} promisified function
* */
function promisify(fn) {
return function () {
var args = Array.prototype.slice.call(arguments);
return new Promise(function(resolve, reject) {
fn.apply(null, args.concat(function (err, result) {
if (err) reject(err);
else resolve(result);
}));
});
}
}
var get_promisified = promisify(get);
var promise = get_promisified('some_url');
promise.then(function (data) {
// corresponds to the resolve function
console.log('successful operation: ', data);
}, function (error) {
console.log(error);
});
承诺总是有决心和拒绝。当您编写异步包装器时,只需调用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上寻找一个现代的包装器,或者像这样编写自己的包装器。
我通常使用的一个简单的泛型函数。
const promisify = (fn, ...args) => {
return new Promise((resolve, reject) => {
fn(...args, (err, data) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
};
如何使用它
函数promify接受带有回调的函数:
const cb = (result) => `The result is ${result}`;
const sum = (a, b, cb) => {
const result = a + b;
cb(result); // passing args to the callback function
}
// using the util
promise = promisify(sum, 3, 1, cb);
promise.then(x => console.log(x)) // 4
您可能不需要这个答案,但这将有助于了解可用实用程序的内部工作原理