Мост между обратными вызовами и промисами - promisify

внешний интерфейс JavaScript модульный тест Promise

Добавить Автора Данная статья является оригинальной, просьба указывать автора и источник для перепечатки

С момента своего создания Promise широко использовался, и это просто артефакт в javascript. Он очень хорошо решает ад обратных вызовов асинхронных методов, предоставляет нам возможность использовать return в асинхронных методах и включает вызов обратного вызова в наше собственное управление вместо того, чтобы передавать его асинхронным функциям. ошибка программы).

Сегодня я хочу представить Promisify, который является мостом между функциями обратного вызова и промисами.

1. Введение в обещание

Что такое обещание? Как следует из названия, это «обещание», превращающее метод, который не является обещанием, в обещание. Например:

// 原有的callback调用
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. Какой обратный вызов называется nodeCallback ?

nodeCallback имеет два условия: 1. Позиция параметра callback-функции в основной функции должна быть последней 2. Первым параметром в callback-функции должен быть error . Например:

  1. Положение параметра функции обратного вызова в основной функции
// 正确
function main(a, b, c, callback) {
    
}

// 错误
function main(callback, a, b, c) {
    
}
  1. Первый параметр в параметрах функции обратного вызова должен быть error
// 正确
function callback(error, result1, result2) {
    
}

// 错误
function callback(result1, result2, error) {
    
}

Таким образом, через nodeCallback мы определяем формат функции, которая может быть промисифицирована, то есть метод, который удовлетворяет форме nodeCallback, мы можем использовать promisify, чтобы сделать его методом, который возвращает промис.

2. Реализация обещания

Давайте вручную реализуем обещание на основе вышеуказанных условий.

Во-первых, обещание должно возвращать функцию, а эта функция должна возвращать обещание.

var promisify = (func) => {
    return function() {
        var ctx = this;
        return new Promise(resolve => {
            return func.call(ctx, ...arguments);
        })
    }
}

Во-вторых, последним параметром оригинальной функции является обратный вызов.

var promisify = (func) => {
    return function() {
        var ctx = this;
        return new Promise(resolve => {
            return func.call(ctx, ...arguments, function() {
                resolve(arguments);
            });
        })
    }
}

Затем первым параметром функции обратного вызова является токен ошибки.

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

Наконец, выполните некоторые оптимизации, такие как настройка этой области, и массив не будет возвращен, когда есть только один возвращаемый параметр.

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

Выше приведено введение и реализация промисификации.На самом деле существует множество методов, предоставляемых сторонними библиотеками, которые используют обратный вызов для достижения асинхронности, и все они имеют формат nodeCallback, поэтому все они могут быть превращены в промисы через промисфай. При встрече эти методы можно использовать более гибко.

Официальный сайт iKcamp:www.ikcamp.com

Посетите официальный веб-сайт, чтобы быстрее ознакомиться со всеми бесплатными курсами обмена: «Продюсер IKcamp | Последние онлайн-программы WeChat Mini | Обмен учебными курсами для начинающих и среднего уровня на основе инструментов разработчика последней версии 1.0». Содержит: статьи, видео, исходный код

Оригинальная новая книга iKcamp «Эффективная разработка мобильного веб-интерфейса» была выпущена на Amazon, JD.com и Dangdang.

【11 ноября】Последнее мероприятие iKcamp в Шанхае

Адрес регистрации:woohoo.events.com/event/54099…

а также“天天练口语”Команда R&D заняла четвертое место в общем списке мини-программ и первое место в категории образования при личном общении.


В 2019 году оригинальная новая книга iKcamp «Практика разработки Koa и Node.js» была продана на JD.com, Tmall, Amazon и Dangdang!