CallbackとPromiseの橋梁——promisify

3816 ワード

CallbackとPromiseの橋梁-----promisify
Promiseは世に出て以来、多くの応用を得て、まさにjavascriptの神器です.これは非常によく非同期の方法を解決しました.私たちは非同期の方法でreturnを使用する能力を提供しています.そしてcalbackの呼び出しを自分の管理に組み入れました.非同期の関数に任せてからはどうすることもできません.
1.promisify紹介
promisifyとは何ですか?その名の通り「プロミス化」して、プロミスではない方法をプロミスに変えます.例を挙げます
fs.readFile('test.js', function(err, data) {
    if (!err) {
        console.log(data);
    } else {
        console.log(err);
    }
});

// promisify 
var readFileAsync = promisify(fs.readFile);
readFileAsync('test.js').then(data => {
    console.log(data);
}, err => {
    console.log(err);
});
この二つの方法は効果的には同等ですが、コントロール的には後ろの書き方が好きです.
では、どのような方法でプロモーションを通じてプロモーションに変えることができますか?ここでは名詞を紹介します.nodeCallback.どのようなcalbackがnodeCallbackですか?
nodeCallbackには2つの条件があります.1.コールバック関数の主関数におけるパラメータ位置は最後でなければなりません.2.コールバック関数パラメータの中の最初のパラメータはerrorでなければなりません.例を挙げます
1.              
//   
function main(a, b, c, callback) {
}

//   
function main(callback, a, b, c) {

}
2.                  error
//   
function callback(error, result1, result2) {

}

//   
function callback(result1, result2, error) {

} 
このように、nodeCallbackを通じて、promisifyの関数のフォーマット、すなわち、nodeCallback形式を満たす方法を定義し、promisifyを通じてpromisifyに変えてpromiseに戻す方法があります.
2.promisifyの実現
以下、上記の条件に基づいて、手動でpromisifyを実現します.
まずpromisifyは一つのfunctionに戻ります.そしてこのfunctionは一つのpromiseに戻ります.
var promisify = (func) => {
    return function() {
        var ctx = this;
        return new Promise(resolve => {
            return func.call(ctx, ...arguments);
        })
    }
}
次に、元funcの最後のパラメータはcalbackです.
var promisify = (func) => {
    return function() {
        var ctx = this;
        return new Promise(resolve => {
            return func.call(ctx, ...arguments, function() {
                resolve(arguments);
            });
        })
    }
}
そして、コールバック関数の最初のパラメータはerrorマークです.
var promisify = (func) => {
    return function() {
        var ctx = this;
        return new Promise((resolve, reject) => {
            return func.call(ctx, ...arguments, function() {
                var args = Array.prototype.map.call(arguments, item => item);
                var err = args.shift();
                if (err) {
                    reject(err);
                } else {
                    resolve(args);
                }
            });
        })
    }
}
最後に、いくつかの最適化を行います.例えば、thisスコープのカスタム、戻りは1つしかない場合、配列に戻りません.
var promisify = (func, ctx) => {
    //       function
    return function() {
        //    this   
        var ctx = ctx || this;
        //       promise
        return new Promise((resolve, reject) => {
            //       promise  func,     ,  ,  callback(callback func       )
            func.call(ctx, ...arguments, function() {
                //              error    
                var args = Array.prototype.map.call(arguments, item => item);
                var err = args.shift();
                //      error
                if (err) {
                    reject(err)
                } else {
                    //   error      resolve  
                    args = args.length > 1 ? args : args[0];
                    resolve(args);
                }
            });
        })
    };
};
テスト
// nodeCallback  func1
var func1 = function(a, b, c, callback) {
    callback(null, a+b+c);
}
// promise   func2
var func2 = promisify(func1);
//      6
func1(1, 2, 3, (err, reuslt) => {
    if (!err) {
        console.log(result); //  6
    }
})
func2(1, 2, 3).then(console.log); //  6
以上がpromisifyの紹介と実現です.実際にはcalbackで非同期を実現する第三者ライブラリが提供する方法は全部nodeCallback形式ですので、promisifyでpromiseにすることができます.これらの方法に出会う時にもっと柔軟に使えます.