기존 콜백 API를 약속으로 변환하려면 어떻게 해야 합니까?
약속으로 작업하고 싶지만 다음과 같은 형식의 콜백 API가 있습니다.
1. DOM 로드 또는 기타 일회성 이벤트:
window.onload; // set to callback
...
window.onload = function() {
};
2. 일반 콜백:
function request(onChangeHandler) {
...
}
request(function() {
// change happened
...
});
3. 노드 스타일 콜백('노드백'):
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) {
...
});
});
});
약속에서 API를 사용하는 방법 및 "약속" 방법은 무엇입니까?
약속에는 상태가 있으며, 보류 중인 것으로 시작하여 다음과 같이 합의할 수 있습니다.
-
기존 콜백 API를 약속으로 변환하려면 어떻게 해야 합니까?
- 계산이 성공적으로 완료되었음을 의미합니다.
- rejected는 계산이 실패했음을 의미합니다.
반환 함수는 절대 던지지 않고 대신 거부를 반환해야 한다고 약속합니다.약속 반환 기능에서 던지면 두 가지 기능을 모두 사용해야 합니다.} catch {
및 a.catch
. Promised API를 사용하는 사람들은 약속들을 기대하지 않는다.JS에서 비동기 API가 어떻게 작동하는지 모르는 경우 먼저 이 답변을 참조하십시오.
1. DOM 로드 또는 기타 일회성 이벤트:
약속 성립 즉, 가 사용 가능한 약속 작성은 가능함을 )..then
를 참조해 주세요.
「」를하는 Promise
ES6:
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
그런 다음 다음과 같은 약속을 사용합니다.
load().then(function() {
// Do things after onload
});
지연을 지원하는 라이브러리의 경우(이 예에서는 $q를 사용하지만 나중에 jQuery도 사용):
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
또는 jQuery와 같은 API를 사용하여 한 번 발생한 이벤트를 후크합니다.
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. 일반 콜백:
JS에서는 콜백이 일반적이기 때문에 이러한 API는 다소 일반적입니다. 그럼 이 때 볼 수 있는 를 볼까요?onSuccess
★★★★★★★★★★★★★★★★★」onFail
:
function getUserData(userId, onLoad, onFail) { …
「」를하는 Promise
ES6:
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
지연을 지원하는 라이브러리의 경우(이 예에서는 jQuery를 사용하지만 위의 $q도 사용):
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
는 jQuery도 합니다.$.Deferred(fn)
하면 '아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아new Promise(fn)
을 사용하다
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
이 jQuery 지연이라는 합니다.resolve
★★★★★★★★★★★★★★★★★」reject
메서드는 "불가침"입니다.jQuery 인스턴스에 바인딩되어 있습니다.지연().모든 lib가 이 기능을 제공하는 것은 아닙니다.
3. 노드 스타일 콜백('노드백'):
노드 스타일 콜백(노드백)에는 콜백이 항상 마지막 인수이고 첫 번째 파라미터가 오류인 특정 형식이 있습니다.먼저 수동으로 프로미스화하겠습니다.
getStuff("dataParam", function(err, data) { …
수신인:
function getStuffAsync(param) {
return new Promise(function(resolve, reject) {
getStuff(param, function(err, data) {
if (err !== null) reject(err);
else resolve(data);
});
});
}
지연을 사용하면 다음 작업을 수행할 수 있습니다(이 예에서는 Q를 사용합니다만, 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;
}
일반적으로 수동으로 너무 많이 프로미스화하지 마십시오.노드를 염두에 두고 설계된 대부분의 프로미스 라이브러리는 노드 8+의 네이티브 약속과 함께 노드백 프로미스화 방법이 내장되어 있습니다.예를들면
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. 노드 스타일의 콜백을 포함한 라이브러리 전체:
여기엔 황금률 따윈 없어, 하나씩 문란하게 해.단, 일부 약속 구현에서는 이를 일괄적으로 수행할 수 있습니다.예를 들어 Bluebird에서는 노드백 API를 약속 API로 변환하는 것이 다음과 같이 간단합니다.
Promise.promisifyAll(API);
또는 노드의 기본 약속:
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}), {});
주의:
- 물론, 당신이 어떤 상황에 있을 때
.then
핸들러에서는, 프로미스 할 필요는 없습니다..then
핸들러는 그 약속의 값을 사용하여 해결하거나 거부합니다..then
핸들러도 좋은 실천이며 약속을 거부합니다.이치 - ★★★★에서는
onload
케이스를 사용하는 것이 좋습니다.addEventListener
onX
.
늘, 는을 사용할 수 .Promise
Node.js
자바스크립트
의 단순하고 인 예Promise
(KISS 방식):
플레인 Javascript 비동기 API 코드:
function divisionAPI (number, divider, successCallback, errorCallback) {
if (divider == 0) {
return errorCallback( new Error("Division by zero") )
}
successCallback( number / divider )
}
Promise
Javascript 비동기 API 코드:
function divisionAPI (number, divider) {
return new Promise(function (fulfilled, rejected) {
if (divider == 0) {
return rejected( new Error("Division by zero") )
}
fulfilled( number / divider )
})
}
한 also도.Promise
할 수 async\await
ES7
의 fullfiled
을 사용하다
function getName () {
return new Promise(function (fulfilled, rejected) {
var name = "John Doe";
// wait 3000 milliseconds before calling fulfilled() method
setTimeout (
function() {
fulfilled( name )
},
3000
)
})
}
async function foo () {
var name = await getName(); // awaits for a fulfilled result!
console.log(name); // the console writes "John Doe" after 3000 milliseconds
}
foo() // calling the foo() method to run the code
.then()
function getName () {
return new Promise(function (fulfilled, rejected) {
var name = "John Doe";
// wait 3000 milliseconds before calling fulfilled() method
setTimeout (
function() {
fulfilled( name )
},
3000
)
})
}
// the console writes "John Doe" after 3000 milliseconds
getName().then(function(name){ console.log(name) })
Promise
는 Node.js와 같이 Node할 수 있습니다.react-native
.
보너스 : 하이브리드 방식
합니다).
function divisionAPI (number, divider, callback) {
return new Promise(function (fulfilled, rejected) {
if (divider == 0) {
let error = new Error("Division by zero")
callback && callback( error )
return rejected( error )
}
let result = number / divider
callback && callback( null, result )
fulfilled( result )
})
}
위의 방법은 오래된 패션 콜백과 Promise 사용법에 대한 결과를 응답할 수 있습니다.
이게 도움이 됐으면 좋겠다.
promise in node로 함수를 변환하기 전.JS
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)
});
난렇 i 가 아니라고 생각한다.window.onload
@Benjamin의 제안은 로드 후에 호출되는지 여부를 감지하지 못하기 때문에 항상 작동합니다.나는 그것에 여러 번 물렸다.하다
function promiseDOMready() {
return new Promise(function(resolve) {
if (document.readyState === "complete") return resolve();
document.addEventListener("DOMContentLoaded", resolve);
});
}
promiseDOMready().then(initOnLoad);
Node.0. Node.js 8.0.0이 되어 있습니다.util.promisify()
Node.js API Promise API 。「 」의 util.promisify()
를 다음에 나타냅니다.
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
readFile('/some/file')
.then((data) => { /* ... */ })
.catch((err) => { /* ... */ });
약속에 대한 향상된 지원 보기
제가 평소에 사용하는 단순한 범용 기능입니다.
const promisify = (fn, ...args) => {
return new Promise((resolve, reject) => {
fn(...args, (err, data) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
};
사용방법
- ★★
promisify
이 있는 .콜백은콜백입니다.
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
이 답을 찾으시는 것은 아닐 것입니다만, 이용 가능한 유틸리티의 내부 구조를 이해하는 데 도움이 됩니다.
8.에는 새로운 Node.js 8.0.0이 util.promisify
util.promisify에 대해 썼습니다.이것은, 모든 함수를 프로미스화하는 용량을 캡슐화한 것입니다.
이는 다른 답변에서 제시한 접근법과 크게 다르지 않지만 핵심 방법이라는 장점이 있으며 추가 종속성이 필요하지 않다.
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
readFile
를 Promise
.
readFile('./notes.txt')
.then(txt => console.log(txt))
.catch(...);
노드 JS에서는 JavaScript 네이티브 약속을 사용할 수 있습니다.
My 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 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
plain old vanilla 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);
});
kriskowal의 Q 라이브러리에는 약속 콜백 기능이 포함되어 있습니다.다음과 같은 방법:
obj.prototype.dosomething(params, cb) {
...blah blah...
cb(error, results);
}
Q.ninvoke로 변환할 수 있습니다.
Q.ninvoke(obj,"dosomething",params).
then(function(results) {
});
콜백을 받는 함수가 몇 개 있고 대신 약속을 반환하고 싶은 경우 이 함수를 사용하여 변환을 수행할 수 있습니다.
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;
}
}
기본 제공 약속 및 비동기 기능이 있는 노드 v7.6+에서 다음을 수행합니다.
// promisify.js
let promisify = fn => (...args) =>
new Promise((resolve, reject) =>
fn(...args, (err, result) => {
if (err) return reject(err);
return resolve(result);
})
);
module.exports = promisify;
사용방법:
let readdir = require('fs').readdir;
let promisify = require('./promisify');
let readdirP = promisify(readdir);
async function myAsyncFn(path) {
let entries = await readdirP(path);
return entries;
}
Node.js 8에서는 다음 npm 모듈을 사용하여 오브젝트 메서드를 즉시 프로미스화할 수 있습니다.
https://www.npmjs.com/package/doasync
util.promisify 및 Proxies를 사용하여 개체를 변경하지 않습니다.메모화는 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);
// ...
});
도 쓸 수 요.call
★★★★★★★★★★★★★★★★★」apply
「 」 「 」 、 「 」
doAsync(myFunc).apply(context, params)
.then(result => { /*...*/ });
ES6에서 네이티브 Promise를 사용하면 set Timeout을 처리할 수 있습니다.
enqueue(data) {
const queue = this;
// returns the Promise
return new Promise(function (resolve, reject) {
setTimeout(()=> {
queue.source.push(data);
resolve(queue); //call native resolve when finish
}
, 10); // resolve() will be called in 10 ms
});
}
실패할 때문에, 이 예에서는 할 이유가 없습니다.reject()
을 사용하다
콜백 스타일 함수는 항상 다음과 같습니다(node.js의 거의 모든 함수는 이 스타일입니다).
//fs.readdir(path[, options], callback)
fs.readdir('mypath',(err,files)=>console.log(files))
이 스타일은 다음과 같은 특징이 있습니다.
콜백 함수는 마지막 인수에 의해 전달됩니다.
콜백 함수는 항상 오류 개체를 첫 번째 인수로 받아들입니다.
따라서 다음과 같은 스타일로 함수를 변환하는 함수를 작성할 수 있습니다.
const R =require('ramda')
/**
* A convenient function for handle error in callback function.
* Accept two function res(resolve) and rej(reject) ,
* return a wrap function that accept a list arguments,
* the first argument as error, if error is null,
* the res function will call,else the rej function.
* @param {function} res the function which will call when no error throw
* @param {function} rej the function which will call when error occur
* @return {function} return a function that accept a list arguments,
* the first argument as error, if error is null, the res function
* will call,else the rej function
**/
const checkErr = (res, rej) => (err, ...data) => R.ifElse(
R.propEq('err', null),
R.compose(
res,
R.prop('data')
),
R.compose(
rej,
R.prop('err')
)
)({err, data})
/**
* wrap the callback style function to Promise style function,
* the callback style function must restrict by convention:
* 1. the function must put the callback function where the last of arguments,
* such as (arg1,arg2,arg3,arg...,callback)
* 2. the callback function must call as callback(err,arg1,arg2,arg...)
* @param {function} fun the callback style function to transform
* @return {function} return the new function that will return a Promise,
* while the origin function throw a error, the Promise will be Promise.reject(error),
* while the origin function work fine, the Promise will be Promise.resolve(args: array),
* the args is which callback function accept
* */
const toPromise = (fun) => (...args) => new Promise(
(res, rej) => R.apply(
fun,
R.append(
checkErr(res, rej),
args
)
)
)
보다 간결하게 하기 위해 위의 예에서는 ramda.js를 사용했습니다.Ramda.js는 기능 프로그래밍에 적합한 라이브러리입니다.위 코드에서는 apply를 사용했습니다(javascript 등).function.prototype.apply
및 추가(javascript 등)function.prototype.push
콜백 스타일 함수를 약속 스타일 함수로 변환할 수 있습니다.
const {readdir} = require('fs')
const readdirP = toPromise(readdir)
readdir(Path)
.then(
(files) => console.log(files),
(err) => console.log(err)
)
약속 및 체크 Err 함수는 버서크 라이브러리에서 자체이며, 기능적인 프로그래밍 라이브러리 fork by ramda.js(제가 만듭니다)입니다.
이 답변이 당신에게 도움이 되길 바랍니다.
es6-promisify
약속하다
const promisify = require('es6-promisify');
const promisedFn = promisify(callbackedFn, args);
참고 자료: https://www.npmjs.com/package/es6-promisify
이런 거 할 수 있어요.
// @flow
const toPromise = (f: (any) => void) => {
return new Promise<any>((resolve, reject) => {
try {
f((result) => {
resolve(result)
})
} catch (e) {
reject(e)
}
})
}
export default toPromise
그럼 쓰세요
async loadData() {
const friends = await toPromise(FriendsManager.loadFriends)
console.log(friends)
}
「 」의 callback
는 "" 입니다.P
★★★★
var P = function() {
var self = this;
var method = arguments[0];
var params = Array.prototype.slice.call(arguments, 1);
return new Promise((resolve, reject) => {
if (method && typeof(method) == 'function') {
params.push(function(err, state) {
if (!err) return resolve(state)
else return reject(err);
});
method.apply(self, params);
} else return reject(new Error('not a function'));
});
}
var callback = function(par, callback) {
var rnd = Math.floor(Math.random() * 2) + 1;
return rnd > 1 ? callback(null, par) : callback(new Error("trap"));
}
callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))
callback("callback", (err, state) => err ? console.error(err) : console.log(state))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P(callback, "promise").then(v => console.log(v)).catch(e => console.error(e))
P
함수는 를 '''로 해야 .callback(error,result)
.
다음은 함수(콜백 API)를 약속으로 변환하는 방법에 대한 구현입니다.
function promisify(functionToExec) {
return function() {
var array = Object.values(arguments);
return new Promise((resolve, reject) => {
array.push(resolve)
try {
functionToExec.apply(null, array);
} catch (error) {
reject(error)
}
})
}
}
// USE SCENARIO
function apiFunction (path, callback) { // Not a promise
// Logic
}
var promisedFunction = promisify(apiFunction);
promisedFunction('path').then(()=>{
// Receive the result here (callback)
})
// Or use it with await like this
let result = await promisedFunction('path');
아마 이미 대답했을지도 모르지만, 보통은 이렇게 하고 있습니다.
// given you've defined this `Future` fn somewhere:
const Future = fn => {return new Promise((r,t) => fn(r,t))}
// define an eventFn that takes a promise `resolver`
const eventFn = resolve => {
// do event related closure actions here. When finally done, call `resolve()`
something.oneventfired = e => {resolve(e)}
}
// invoke eventFn in an `async` workflowFn using `Future`
// to obtain a `promise` wrapper
const workflowFn = async () => {await Future(eventFn)}
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
indexedDb
이벤트 래퍼를 사용하여 사용을 단순화합니다.
이런 요.Future
더 범용적으로
class PromiseEx extends Promise {
resolve(v,...a) {
this.settled = true; this.settledValue = v;
return(this.resolve_(v,...a))
}
reject(v,...a) {
this.settled = false; this.settledValue = v;
return(this.reject_(v,...a))
}
static Future(fn,...args) {
let r,t,ft = new PromiseEx((r_,t_) => {r=r_;t=t_})
ft.resolve_ = r; ft.reject_ = t; fn(ft,...args);
return(ft)
}
}
이 링크는 네크로맨싱을 조금 하면 도움이 될 것 같습니다.
TLDR: 이 답변의 끝에 있는 스니펫의 예를 참조하십시오.
기대라고 할 수 있는 쓰기/쓰기 기능
a cb(error,result)
★★★★★★★★★★★★★★★★★」new Promise (...)
변경
promiseToCB
되어 있습니다.cbToPromise
(error, result)를 사용하여 마지막 인수를 호출하도록 코드화된 기존 함수를 변환하고 내보냅니다.- 래핑된 함수가 두 개 이상의 결과를 제공하는 경우 결과는 일련의 결과입니다.
- : ★★
cb(undefined,path,stat)
--->resolve([path,stat])
cb(undefined,[path,stat])
asPromise
할 수 , .asCallback
를 사용하면 함수를 하여 "New Function"을 호출할 수 .cb(err,result)
, 어느 할 수
샘플 함수
각 샘플은 2개의 인수를 사용하여 난수에 따라 해결/수정/수정합니다.
arg2는 강제 통과 또는 실패에도 사용할 수 있습니다.("-pass" 또는 "-fail"의 경우).
기존 기능 랩
- 현재 "this "this"(이것)를 사용합니다).
promiseToCB(function myFunc(){},newThis);
)
promiseToCB(function sampleFunc1(arg1,arg2) {
console.log("deciding:",arg1,arg2);
return new Promise(function(resolve,reject){
const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
resolve([arg1,arg2,"all good"].join("-"));
}
},2000);
});
});
cbToPromise('sampleFunc2',function someOtherName(arg1,arg2,cb) {
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
cb(undefined,[arg1,arg2,"all good"].join("-"));
}
},2000);
},local);
또는 새로운 함수를 코드화하여 래퍼를 포함합니다.
function sampleFunc3(arg1,arg2) {return asPromise(arguments,function(resolve,reject){
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
resolve([arg1,arg2,"all good"].join("-"));
}
},2000);
});}
function sampleFunc4(arg1,arg2) {return asCallback(arguments,function(cb){
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
cb(undefined,[arg1,arg2,"all good"].join("-"));
}
},2000);
});}
위의 기능을 테스트하다
const local = {};
promiseToCB(function sampleFunc1(arg1,arg2) {
console.log("deciding:",arg1,arg2);
return new Promise(function(resolve,reject){
const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
resolve([arg1,arg2,"all good"].join("-"));
}
},2000);
});
});
cbToPromise('sampleFunc2',function someOtherName(arg1,arg2,cb) {
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
cb(undefined,[arg1,arg2,"all good"].join("-"));
}
},2000);
},local);
function sampleFunc3(arg1,arg2) {return asPromise(arguments,function(resolve,reject){
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
resolve([arg1,arg2,"all good"].join("-"));
}
},2000);
});}
function sampleFunc4(arg1,arg2) {return asCallback(arguments,function(cb){
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
cb(undefined,[arg1,arg2,"all good"].join("-"));
}
},2000);
});}
const log=console.log.bind(console),info=console.info.bind(console),error=console.error.bind(console);
sampleFunc1("sample1","promise").then (log).catch(error);
local.sampleFunc2("sample2","promise").then (log).catch(error);
sampleFunc3("sample3","promise").then (log).catch(error);
sampleFunc4("sample4","promise").then (log).catch(error);
sampleFunc1("sample1","callback",info);
local.sampleFunc2("sample2","callback",info);
sampleFunc3("sample3","callback",info);
sampleFunc4("sample4","callback",info);
sampleFunc1("sample1","promise-pass").then (log).catch(error);
local.sampleFunc2("sample2","promise-pass").then (log).catch(error);
sampleFunc3("sample3","promise-pass").then (log).catch(error);
sampleFunc4("sample4","promise-pass").then (log).catch(error);
sampleFunc1("sample1","callback-pass",info);
local.sampleFunc2("sample2","callback-pass",info);
sampleFunc3("sample3","callback-pass",info);
sampleFunc4("sample4","callback-pass",info);
sampleFunc1("sample1","promise-fail").then (log).catch(error);
local.sampleFunc2("sample2","promise-fail").then (log).catch(error);
sampleFunc3("sample3","promise-fail").then (log).catch(error);
sampleFunc4("sample4","promise-fail").then (log).catch(error);
sampleFunc1("sample1","callback-fail",info);
local.sampleFunc2("sample2","callback-fail",info);
sampleFunc3("sample3","callback-fail",info);
sampleFunc4("sample4","callback-fail",info);
var cpArgs = Array.prototype.slice.call.bind(Array.prototype.slice);
function promiseToCB (nm,fn,THIS) {
if (typeof nm==='function') {
THIS=fn;fn=nm;nm=fn.name;
}
THIS=THIS||this;
const func = function () {
let args = cpArgs(arguments);
if (typeof args[args.length-1]==='function') {
const cb = args.pop();
return fn.apply(THIS,args).then(function(r){
cb (undefined,r);
}).catch(cb);
} else {
return fn.apply(THIS,args);
}
};
Object.defineProperty(func,'name',{value:nm,enumerable:false,configurable: true});
if (THIS[nm]) delete THIS[nm];
Object.defineProperty(THIS,nm,{value:func,enumerable:false,configurable: true});
return func;
}
function cbToPromise (nm,fn,THIS) {
if (typeof nm==='function') {
THIS=fn;fn=nm;nm=fn.name;
}
THIS=THIS||this;
const func = function () {
let args = cpArgs(arguments);
if (typeof args[args.length-1]==='function') {
return fn.apply(THIS,args);
} else {
return new Promise(function(resolve,reject){
args.push(function(err,result){
if (err) return reject(err);
if (arguments.length==2) {
return resolve(result);
}
return resolve(cpArgs(arguments,1));
});
fn.apply(THIS,args);
});
}
};
Object.defineProperty(func,'name',{value:nm,enumerable:false,configurable: true});
if (THIS[nm]) delete THIS[nm];
Object.defineProperty(THIS,nm,{value:func,enumerable:false,configurable: true});
return func;
}
function asPromise (args,resolver,no_err) {
const cb = args[args.length-1],
promise = new Promise(resolver);
return (typeof cb==='function') ? promise.then(function(result){return cb(no_err,result)}).catch(cb) : promise;
}
function asCallback (args,wrap,no_err) {
const cb = args[args.length-1],
promise=new Promise(function resolver(resolve,reject) {
return wrap (function (err,result) {
if (err) return reject(err);
resolve(result);
});
});
return (typeof cb==='function') ? promise.then(function(result){return cb(no_err,result)}).catch(cb) : promise;
}
function cbPromiseTest(){
/*global sampleFunc1,sampleFunc2*/
const local = {};
promiseToCB(function sampleFunc1(arg1,arg2) {
console.log("deciding:",arg1,arg2);
return new Promise(function(resolve,reject){
const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
resolve([arg1,arg2,"all good"].join("-"));
}
},2000);
});
});
cbToPromise('sampleFunc2',function someOtherName(arg1,arg2,cb) {
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
cb(undefined,[arg1,arg2,"all good"].join("-"));
}
},2000);
},local);
function sampleFunc3(arg1,arg2) {return asPromise(arguments,function(resolve,reject){
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){reject([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
resolve([arg1,arg2,"all good"].join("-"));
}
},2000);
});}
function sampleFunc4(arg1,arg2) {return asCallback(arguments,function(cb){
console.log("deciding:",arg1,arg2);
const timer = setTimeout(function(){cb([arg1,arg2,"ouch"].join("-"));},5000);
setTimeout(function(){
if (arg2.endsWith("-pass") || (!arg2.endsWith("-fail") && Math.random()<0.5)) {
console.log("complete:",arg1,arg2);
clearTimeout(timer);
cb(undefined,[arg1,arg2,"all good"].join("-"));
}
},2000);
});}
const log=console.log.bind(console),info=console.info.bind(console),error=console.error.bind(console);
sampleFunc1("sample1","promise").then (log).catch(error);
local.sampleFunc2("sample2","promise").then (log).catch(error);
sampleFunc3("sample3","promise").then (log).catch(error);
sampleFunc4("sample4","promise").then (log).catch(error);
sampleFunc1("sample1","callback",info);
local.sampleFunc2("sample2","callback",info);
sampleFunc3("sample3","callback",info);
sampleFunc4("sample4","callback",info);
sampleFunc1("sample1","promise-pass").then (log).catch(error);
local.sampleFunc2("sample2","promise-pass").then (log).catch(error);
sampleFunc3("sample3","promise-pass").then (log).catch(error);
sampleFunc4("sample4","promise-pass").then (log).catch(error);
sampleFunc1("sample1","callback-pass",info);
local.sampleFunc2("sample2","callback-pass",info);
sampleFunc3("sample3","callback-pass",info);
sampleFunc4("sample4","callback-pass",info);
sampleFunc1("sample1","promise-fail").then (log).catch(error);
local.sampleFunc2("sample2","promise-fail").then (log).catch(error);
sampleFunc3("sample3","promise-fail").then (log).catch(error);
sampleFunc4("sample4","promise-fail").then (log).catch(error);
sampleFunc1("sample1","callback-fail",info);
local.sampleFunc2("sample2","callback-fail",info);
sampleFunc3("sample3","callback-fail",info);
sampleFunc4("sample4","callback-fail",info);
}
cbPromiseTest();
'어느새'가 .resolve
a. a. a.reject
비동기 래퍼를 쓸 때는 해결 방법을 호출하기만 하면 됩니다.
다음과 같이 콜백을 하는 거의 모든 함수에 대해 래퍼 함수를 작성할 수 있습니다.
const myAsyncWrapper = (...params) =>
new Promise((resolve, reject) =>
someFunctionWithCallback(...params, (error, response) =>
error ? reject(error) : resolve(response)
)
);
콜백에서 약속으로 변환 함수를 작성하려면 다음 절차를 수행합니다.
const promisify =
(functionWithCallback) =>
(...params) =>
new Promise((resolve, reject) =>
functionWithCallback(...params, (error, response) =>
error ? reject(error) : resolve(response)
)
);
이 래퍼 기능의 개념은 오래된 라이브러리 또는 SDK를 사용할 때 특히 유용합니다.예를 들어 Facebook Graph API의 JavaScript SDK는 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)))
);
프로미셔는 때로는 훌륭하지만, 이와 같은 특정 인스턴스에서는 작동하지 않습니다.이럴 때 기써브에서 현대판 포장지를 찾거나 이렇게 직접 써보세요.
콜백 기반 함수의 특성을 미리 알고 있기 때문에 콜백 기반 함수를 Promise를 반환하는 동등한 함수로 변환하는 함수를 만들 수 있습니다.
콜백은 함수의 마지막 인수입니다.
오류가 있을 경우 항상 첫 번째 인수가 콜백에 전달됩니다.
오류 발생 후 반환값이 콜백에 전달됩니다.
function promisify(yourCallbackApi) { return function promisified(...args) { return new Promise((resolve, reject) => { // newArgs=[..args,callback] const newArgs = [ ...args, function (err, result) { if (err) { return reject(err); } resolve(result); }, ]; // invoke yourCallbackApi with the new list of arguments yourCallbackApi(...newArgs); }); }; }
5년 정도 늦었지만, 콜백 API에서 기능을 가져와 약속으로 바꾸는 Promesify 버전을 여기에 올렸습니다.
const promesify = fn => {
return (...params) => ({
then: cbThen => ({
catch: cbCatch => {
fn(...params, cbThen, cbCatch);
}
})
});
};
이 매우 간단한 버전을 보시기 바랍니다.https://gist.github.com/jdtorregrosas/aeee96dd07558a5d18db1ff02f31e21a
언급URL : https://stackoverflow.com/questions/22519784/how-do-i-convert-an-existing-callback-api-to-promises
'programing' 카테고리의 다른 글
이스케이프된 URL 매개 변수 가져오기 (0) | 2022.12.21 |
---|---|
MySQL에서 사용 가능한 데이터 유형 나열 (0) | 2022.12.21 |
상위 행을 삭제하거나 업데이트할 수 없음: 외부 키 제약 조건이 실패합니다. (0) | 2022.12.11 |
MySQL 테이블이 마지막으로 업데이트된 날짜를 확인하려면 어떻게 해야 합니까? (0) | 2022.12.11 |
PHP cURL을 사용하여 JSON 데이터를 게시하는 방법 (0) | 2022.12.11 |