[javascript] 기존 콜백 API를 약속으로 변환하려면 어떻게합니까?

약속으로 작업하고 싶지만 다음과 같은 형식의 콜백 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) {
            ...
        });
    });
});

약속에서 API로 어떻게 작업합니까? 어떻게 “약속”합니까?



답변

약속에는 상태가 있으며 보류 중으로 시작하여 다음과 같이 해결할 수 있습니다.

  • 계산이 성공적으로 완료 되었음을 의미합니다.
  • 거부 계산이 실패했음을 의미한다.

약속 반환 함수 는 절대 던져서 는 안되며 거부를 반환해야합니다. 약속 반환 함수에서 던지면 a } catch { a를 모두 사용해야합니다 .catch. 약속 된 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;
}

또는 API와 같은 jQuery를 사용하여 한 번 발생하는 이벤트에 연결하십시오.

function done() {
    var d = $.Deferred();
    $("#myObject").once("click",function() {
        d.resolve();
    });
    return d.promise();
}

2. 일반 콜백 :

이 API는 꽤 일반적이기 때문에… 콜백은 JS에서 일반적입니다. 가지고있는 일반적인 경우에서 살펴 보자 onSuccessonFail:

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 지연 resolvereject메소드가 “분리 가능” 하다는 사실을 이용합니다 . 즉. 그것들은 jQuery.Deferred () 의 인스턴스 에 바인딩됩니다 . 모든 라이브러리가이 기능을 제공하는 것은 아닙니다.

3. 노드 스타일 콜백 ( “nodeback”) :

노드 스타일 콜백 (노드 백)은 콜백이 항상 마지막 인수이고 첫 번째 매개 변수가 오류 인 특정 형식을 갖습니다. 먼저 하나를 수동으로 약속합시다.

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 는 선호 하는 새로운 구문 지원하지만 ).

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);

또는 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}), {});

노트:

  • 물론, 당신이 .then핸들러 에있을 때 당신은 일을 약속 할 필요가 없습니다. .then처리기 에서 약속을 반환하면 해당 약속의 값으로 해결되거나 거부됩니다. .then처리기 에서 던지는 것도 좋은 습관이며 약속을 거부합니다. 이것은 유명한 약속 던지기 안전입니다.
  • 실제로 onload는을 사용 addEventListener하지 않아야합니다 onX.

답변

오늘, 내가 사용할 수 Promise있는 Node.js일반 자바 스크립트 방법으로.

Promise( KISS 방식으로) 간단한 기본 예 :

일반 자바 스크립트 비동기 API 코드 :

function divisionAPI (number, divider, successCallback, errorCallback) {

    if (divider == 0) {
        return errorCallback( new Error("Division by zero") )
    }

    successCallback( number / divider )

}

Promise 자바 스크립트 비동기 API 코드 :

function divisionAPI (number, divider) {

    return new Promise(function (fulfilled, rejected) {

        if (divider == 0) {
            return rejected( new Error("Division by zero") )
        }

        fulfilled( number / divider )

     })

}

( 이 아름다운 출처를 방문 하는 것이 좋습니다 )

또한 Promise함께 사용할 수 있습니다 async\awaitES7A의 프로그램 흐름 대기하기 위해 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) })

PromiseNode.js를 기반으로하는 모든 플랫폼에서도 사용할 수 있습니다 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 사용에 대한 결과에 응답 할 수 있습니다.

도움이 되었기를 바랍니다.


답변

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)
});


답변

window.onload@ Benjamin 의 제안은로드 후 호출되는지 여부를 감지하지 못하기 때문에 항상 작동 한다고 생각 하지 않습니다. 나는 여러 번 물렸다. 다음은 항상 작동해야하는 버전입니다.

function promiseDOMready() {
    return new Promise(function(resolve) {
        if (document.readyState === "complete") return resolve();
        document.addEventListener("DOMContentLoaded", resolve);
    });
}
promiseDOMready().then(initOnLoad);


답변

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) => { /** ... **/ });

약속에 대한 향상된 지원 참조


답변

Node.js 8.0.0의 릴리스 후보에는 모든 기능을 약속하는 기능을 캡슐화 하는 새로운 유틸리티 util.promisify( util.promisify 에 대해 작성 했습니다 )가 있습니다.

그것은 다른 답변에서 제안 된 접근 방식과 크게 다르지 않지만 핵심 방법이며 추가 종속성이 필요하지 않다는 이점이 있습니다.

const fs = require('fs');
const util = require('util');

const readFile = util.promisify(fs.readFile);

그런 다음 readFilenative을 반환하는 메서드가 Promise있습니다.

readFile('./notes.txt')
  .then(txt => console.log(txt))
  .catch(...);


답변

Node 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