массив обратных вызовов как Promise? - PullRequest
1 голос
/ 29 мая 2019

Я работаю через старый код, работающий с сетевыми запросами, используя библиотеку RPC / YUI. По сути, он создает теги для обработки сетевых запросов. Для них нет никаких обещаний. Кроме того, из-за поддержки IE11 мы не можем использовать нативный объект Promise. Наш процесс сборки не использует никаких зависимостей от NPM, поэтому мы не можем использовать какие-либо связанные с babel полифилы.

Существует ошибка, над которой я работаю, чтобы исправить то, что аргумент ignoreError перезаписывается каждый раз, когда другая функция вызывает ту же функцию .... очевидно! У нас есть несколько функций, вызывающих эту библиотеку функций сетевого запроса. Иногда мы хотим игнорировать ошибку, иногда нет.

Каков идеальный способ хранения нескольких сделанных запросов и соответствующих им обратных вызовов с ошибками, чтобы вызывался соответствующий элемент?

пример:

var rpcUrl,
rpcRetries,
rpcIgnoreError;

// main function that sets some globals:
rpc: function(url, retries, ignoreError) {
  rpcUrl = url;
  rpcRetries = retries;
  rpcIgnoreError = ignoreError;
  this.doRpc();
},
// calls the YUI library to initialize network script:
doRpc: function() {
  YAHOO.util.Get.script(rpcUrl, {
    onFailure: function() {
      this.callbackError(true);
    },
    timeout: 55000
  });
},
// YUI callback
callbackError: function(retry) {
  if (retry && rpcRetries > 0) {
    rpcRetries = rpcRetries - 1;
    this.doRpc();
  } else {
    // ** how do i know this error handling is for the script which failed?
    if (!rpcIgnoreError) {
      this.populateFormStatus(6);
    }
  }
},

Теперь у нас есть несколько функций, вызывающих rpc(), таких как:

sendConfig: function() {
  this.rpc(urlForEndpoint, 3, true);
},
sendUser: function() {
  this.rpc(urlForEndpoint, 3, false);
},
sendWidget: function() {
  this.rpc(urlForEndpoint, 3, false);
},

Я обеспокоен тем, что создание массива обратных вызовов не гарантирует, что каждый элемент обрабатывается соответствующим обработчиком.

Я мог бы сделать что-то вроде создания константы карты:

var RPC_ERR_CB = {
    sendConfig: false,
    sendUser: true,
    sendWidget: true
};

// а затем в обратном вызове onFailure я могу прочитать src тега script:

...
doRpc: function() {
  YAHOO.util.Get.script(rpcUrl, {
    onFailure: function() {
      var hasCB = Object.keys(RPC_ERR_CB).some(function(item) {
        return arguments[0].src.indexOf(RPC_ERR_CB[item]) <= 0;
     });
      if (hasCB) {
        this.callbackError(true);
      }
    },
    timeout: 55000
  });
},

Надеюсь, это имеет смысл ... СПАСИБО!

Ответы [ 2 ]

1 голос
/ 29 мая 2019

Если вы не можете использовать Обещания или Классы ES6, ваши возможности становятся несколько ограниченными. Если это вообще возможно, я бы порекомендовал прикусить пулю при получении процесса трансплантации Babel, чтобы вы могли воспользоваться более новыми функциями без необходимости прекращения поддержки IE11.

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

function RpcRequest (url, retries, ignoreError) {
  this.url = url
  this.retries = retries
  this.ignoreError = ignoreError
}

RpcRequest.prototype.send = function() {
  YAHOO.util.Get.script(this.url, {
    onFailure: function() {
      this.callbackError(true);
    },
    timeout: 55000
  });
}

RpcRequest.prototype.callbackError = function(retry) {
  if (retry && this.retries > 0) {
    this.retries = this.retries - 1;
    this.send();
  } else {
    if (!this.ignoreError) {

      // ...

    }
  }
}

// Somewhere else, initiate a request
var requestOne = new RpcRequest("http://blah", 3, false)
requestOne.send()

Что-то, что я заметил, просматривая ваш код: код, который создает запрос, не знает, был ли запрос успешным или нет. И когда у вас есть ошибка, вызывающий контекст ничего не знает об этой ошибке. Я посмотрел на библиотеку, которую вы упомянули, и в ней действительно есть некоторый контекст, который вы можете передать.

Если бы я немного переписал это, я бы сделал что-то вроде этого, чтобы вывести ошибку в контекст вашего вызова:

RpcRequest.prototype.send = function(callback) {
  YAHOO.util.Get.script(this.url, {
    onFailure: function(context) {
      if( this.ignoreError ) {
        context.ignoredError = true
        callback(null, context);
        return;
      }

      var retError = new Error('Failure doing something!');
      retError.context = context;

      callback(retError);
    },
    onSuccess: function(context) {
      callback(null, context);
    },
    timeout: 55000
  });
}

// Somewhere else in the code...
sendWidget: function() {
  var request = new RpcRequest(urlForEndpoint, 3, false)
  request.send(function(err, result) {
    if( err ) {
      console.error('Failed at doing a widget thing:', err.context);
      // maybe even:
      // throw err;
      return;
    }

    if( result.ignoredError ) {
      console.warn('Ignored an error on the widget thing:', result);
      return;
    }

    console.log('Success on the widget thing!', result);
  })
}
1 голос
/ 29 мая 2019

Вы можете передать значения в doRpc, затем вы можете передать их в callbackError или обработать их в doRpc (как ваш пример кода в конце).Это предотвратит изменение глобальной переменной на вас.

...