Рассказ о нескольких фронтенд-асинхронных решениях

внешний интерфейс

В первую очередь сделайте рекламу своим друзьям, это знают большие ребята в кругу и те, кто собирается вступить в круг,Определенный курс и недорогие ресурсы на различных платформах, таких как Geek, Kaikeba и т. Д., Пакетные обновления, в руках этого передового приятеля по разработке и в то же время для службы руководства интервью и технического руководства для тех, кто собирается войти в отрасль, добавьте его!

Среда выполнения языка Javascript является однопоточной. То есть за один раз может быть выполнена только одна задача. Если задач несколько, их нужно ставить в очередь и выполнять одну за другой — завершается предыдущая задача, а затем выполняется следующая задача.

Этот режим выполнения прост в реализации, и среда выполнения относительно проста. Однако с ростом сложности внешнего интерфейса и увеличением количества транзакций и запросов этот однопоточный метод выполнения неизбежно будет неэффективным в сложном бизнесе.Поскольку одна задача занимает много времени, следующие задачи должны быть выполнены. поставлены в очередь, что задержит выполнение всей программы. Обычные браузеры не отвечают (притворная смерть), часто потому, что определенный фрагмент кода Javascript выполняется в течение длительного времени (например, бесконечный цикл), в результате чего вся страница зависает на этом месте, и другие задачи не могут быть выполнены.

Чтобы избежать и решить эту проблему, язык JS делит режим выполнения задачи на асинхронный и синхронный. "Синхронный режим" - это режим предыдущего пункта. Последняя задача дожидается окончания предыдущей задачи, а затем выполняет ее. Порядок выполнения программы согласован и синхронен с порядком расположения задач; "асинхронный" режим" совершенно разный. Каждая задача имеет одну или несколько callback-функций (callback), после окончания предыдущей задачи, вместо выполнения последней задачи, выполняется callback-функция, а последняя задача выполняется, не дожидаясь окончания предыдущей задачи, поэтому порядок выполнения программы такой же, как и задачи, порядок сортировки непоследовательный и асинхронный.

«Асинхронный режим» очень важен. На стороне браузера операции, которые занимают много времени, должны выполняться асинхронно, чтобы избежать зависания браузера.Лучший пример — операции Ajax. На стороне сервера «асинхронный режим» является даже единственным режимом, поскольку среда выполнения является однопоточной, и если разрешить синхронное выполнение всех HTTP-запросов, производительность сервера резко снизится и он быстро перестанет отвечать.

1. Функция обратного вызова

Асинхронное программирование самый простой метод.

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

Английское определение функции обратного вызова: обратный вызов — это функция, которая передается в качестве аргумента другой функции и выполняется после завершения ее родительской функции.

Буквально функция обратного вызова является параметром, и эта функция передается в качестве параметра другой функции.Когда функция выполняется, выполняется переданная функция. Этот процесс называется обратным вызовом.

В JavaScript функция обратного вызова определяется следующим образом: функция A передается как параметр (ссылка на функцию) другой функции B, и эта функция B выполняет функцию A. Мы говорим, что функция A называется функцией обратного вызова. Если имя (функция-выражение) отсутствует, она называется анонимной функцией обратного вызова.

Приведу в качестве аналогии обычный жизненный пример: после окончания свидания вы отправляете свою девушку домой, а уходя, обязательно говорите: «Когда вернешься домой, напиши мне, я очень за тебя волнуюсь». "Тогда твоя девушка идет домой, я пошлю тебе сообщение позже. По сути, это процесс обратного вызова. Вы оставляете параметрическую функцию (просите свою девушку отправить вам сообщение) своей девушке, а затем ваша девушка идет домой, и действие по возвращению домой является основной функцией. Сначала она должна вернуться домой, после того как основная функция будет выполнена, а затем выполнить переданную функцию, а затем вы получите сообщение.

Предположим, что есть две функции f1 и f2, причем последняя ожидает результата выполнения первой.

f1();
f2(); 

Если f1 требует много времени, рассмотрите возможность перезаписи f1 и записи f2 в качестве функции обратного вызова f1.

function f1(callback){setTimeout(function () {// f1的任务代码callback();}, 1000);}

Код выполнения становится следующим:

f1(f2);

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

другой пример:

//定义主函数,回调函数作为参数
function A(callback) {
    callback();  
    console.log('我是主函数');      
}

//定义回调函数
function B(){
    setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作  
}

//调用主函数,将函数B传进去
A(B);

//输出结果
我是主函数
我是回调函数

В приведенном выше коде мы сначала определяем основную функцию и функцию обратного вызова, а затем вызываем основную функцию и передаем функцию обратного вызова.

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

Вот более приземленный пример:

<strong>问:你有事去隔壁寝室找同学,发现人不在,你怎么办呢?</strong><strong>方法1</strong>,每隔几分钟再去趟隔壁寝室,看人在不<strong>方法2</strong>,拜托与他同寝室的人,看到他回来时叫一下你 前者是轮询,后者是回调。 那你说,我直接在隔壁寝室等到同学回来可以吗? 可以啊,只不过这样原本你可以省下时间做其他事,现在必须浪费在等待上了。把原来的非阻塞的异步调用变成了阻塞的同步调用。 JavaScript的回调是在异步调用场景下使用的,使用回调性能好于轮询。

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

При этом дополняются сценарии применения и преимущества и недостатки callback-функции:

  • Загрузка ресурсов: выполнение обратных вызовов после динамической загрузки js-файлов, выполнение обратных вызовов после загрузки iframe, обратные вызовы операций ajax, обратные вызовы выполнения загрузки изображений, AJAX и т. д.
  • События DOM и события Node.js основаны на механизме обратного вызова (обратные вызовы Node.js могут иметь многоуровневые проблемы вложенности обратных вызовов).
  • Время задержки setTimeout равно 0. Этот хак часто используется.Функция, вызываемая settimeout, на самом деле является воплощением обратного вызова.
  • Сцепленные вызовы: при цепочке легко реализовать цепные вызовы в методе установки (или в методе, который сам не возвращает значение), в то время как в геттере относительно сложно реализовать цепные вызовы Вызов, потому что вам нужно, чтобы оценщик возвращал данные, которые вам нужны, вместо указателя this, если вы хотите реализовать связанные методы, вы можете использовать функцию обратного вызова для ее реализации.
  • Вызовы функций setTimeout и setInterval получают свои возвращаемые значения. Так как две функции являются асинхронными, то есть время их вызова и основной процесс программы относительно независимы, нет возможности ждать их возвращаемых значений в основном теле, и программа не будет останавливаться и ждать, когда они открыты, иначе смысл setTimeout и setInterval будет потерян, поэтому использовать return бессмысленно, и вы можете использовать только callback. Значение обратного вызова состоит в том, чтобы уведомить прокси-функцию о результате выполнения таймера для своевременной обработки.

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

2. Объект обещания

С выходом стандарта ES6 решение для обработки асинхронных потоков данных претерпело новые изменения.

promise

является одним из них. Все мы знаем, что в традиционных ajax-запросах, когда между асинхронными запросами существует зависимость данных, могут генерироваться уродливые многоуровневые обратные вызовы, которые легко вызовут путаницу в логике кода, которую потом будет непросто читать и поддерживать. как «ад обратного вызова». С другой стороны, код обработки ошибок часто сочетается с обычным бизнес-кодом, что делает код чрезвычайно уродливым. Чтобы сделать программирование лучше, нам нужно ввестиpromiseдля уменьшения сложности асинхронного программирования.

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

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

f1().then(f2);

Для функции f1 используйте Jquery для реализации следующей перезаписи:

function f1(){var dfd = $.Deferred();setTimeout(function () {// f1的任务代码dfd.resolve();}, 500);return dfd.promise;}

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

Давайте возьмем еще один пример формулирования нескольких функций обратного вызова в виде:

f1().then(f2).then(f3);

При указании callback-функции при возникновении ошибки ее вид такой:

f1().then(f2).fail(f3);

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

Давайте подробнее об обещаниях: обещания на самом деле являются специальным объектом Javascript, который отражает «окончательное значение асинхронной операции». «Обещание» буквально означает «ожидаемый», поэтому оно также представляет собой обещание, что этот объект в конечном итоге вернет вам значение, независимо от того, будет ли ваша асинхронная операция успешной или нет.

пример кода

const promise = new Promise((resolve, reject) => {
  $.ajax('https://github.com/users', (value) =>  {
    resolve(value);
  }).fail((err) => {
    reject(err);
  });
});
promise.then((value) => {
  console.log(value);
},(err) => {
  console.log(err);
});
//也可以采取下面这种写法
promise.then(value => console.log(value)).catch(err => console.log(err));

Вышеуказанный пример будет вызываться после успеха запроса AJAXresolveФункция обратного вызова для обработки результата, вызываемая в случае сбоя запроса.rejectФункция обратного вызова для обработки ошибок. Объект Promise содержит три состояния: ожидание, выполнение и отклонение. Эти три состояния могут быть аналогичны нашим обычным ожиданиям, успеху и ошибке в процессе запроса данных ajax. После отправки исходного запроса состояние Pending означает, что он ожидает завершения обработки Это состояние является промежуточным и односторонним необратимым. После того, как значение успешно получено, состояние становится выполненным, а затем успешно полученное значение сохраняется и может быть вызвано позже, вызвавthenФункция обратного вызова, переданная методом для дальнейшей обработки. И если это не удается, статус становится отклоненным, и ошибка может быть выброшена или вызванаrejectметод обработки.

Основной синтаксис обещания выглядит следующим образом.

  • Экземпляры промисов должны реализовывать метод then

  • then() должен иметь возможность принимать две функции в качестве аргументов

  • then() должен возвращать экземпляр Promise

    eg
    <script src="https://cdn.bootcss.com/bluebird/3.5.1/bluebird.min.js"></script>//如果低版本浏览器不支持Promise,通过cdn这种方式
          <script type="text/javascript">
            function loadImg(src) {
                var promise = new Promise(function (resolve, reject) {
                    var img = document.createElement('img')
                    img.onload = function () {
                        resolve(img)
                    }
                    img.onerror = function () {
                        reject('图片加载失败')
                    }
                    img.src = src
                })
                return promise
            }
            var src = 'https://www.imooc.com/static/img/index/logo_new.png'
            var result = loadImg(src)
            result.then(function (img) {
                console.log(1, img.width)
                return img
            }, function () {
                console.log('error 1')
            }).then(function (img) {
                console.log(2, img.height)
            })
         </script>
    作者:浪里行舟
    链接:https://juejin.cn/post/6844903620878532616
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    

Promise также может делать больше вещей, например, если есть несколько асинхронных задач, вам нужно сначала выполнить задачу 1. Если это удастся, затем выполнить задачу 2. Если какая-либо задача не удалась, она не продолжится и выполнит функцию обработки ошибок. Чтобы выполнять такие асинхронные задачи последовательно, без промисов, вам нужно писать слои вложенного кода.

С промисами мы просто пишемjob1.then(job2).then(job3).catch(handleError);Где job1, job2 и job3 являются объектами Promise.

Например, мы хотим загрузить второе изображение после загрузки первого изображения, если одно из них не выполняется, выполните функцию ошибки:

var src1 = 'https://www.imooc.com/static/img/index/logo_new.png'
        var result1 = loadImg(src1) //result1是Promise对象
        var src2 = 'https://img1.mukewang.com/545862fe00017c2602200220-100-100.jpg'
        var result2 = loadImg(src2) //result2是Promise对象
        result1.then(function (img1) {
            console.log('第一个图片加载完成', img1.width)
            return result2  // 链式操作
        }).then(function (img2) {
            console.log('第二个图片加载完成', img2.width)
        }).catch(function (ex) {
            console.log(ex)
        })

Здесь следует отметить, что:Метод then может вызываться несколько раз одним и тем же обещанием, тогда метод должен возвращать объект обещания.. В приведенном выше примере, если result1.then не возвращает экземпляр Promise в виде простого текста, он по умолчанию использует свой собственный экземпляр Promise, то есть result1, а result1.then возвращает экземпляр result2, а затем выполняет result2.then, который является фактически казнен .потом.

Общие методы промисов

      Помимо последовательного выполнения нескольких асинхронных задач, промисы также могут выполнять асинхронные задачи параллельно..

Представьте себе систему страничного чата. Нам нужно получить личную информацию пользователя и список друзей с двух разных URL соответственно. Эти две задачи могут выполняться параллельно. Promise.all() реализован следующим образом:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
    console.log(results); // 获得一个Array: ['P1', 'P2']
});

Иногда несколько асинхронных задач необходимы для обеспечения отказоустойчивости. Например, чтобы прочитать личную информацию пользователя с двух URL-адресов одновременно, вам нужно только сначала получить результат. В этом случае используйте Promise.race() для реализации:

var p1 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 500, 'P1');
});
var p2 = new Promise(function (resolve, reject) {
    setTimeout(resolve, 600, 'P2');
});
Promise.race([p1, p2]).then(function (result) {
    console.log(result); // 'P1'
});

Поскольку p1 выполняется быстрее, функция then() в Promise получит результат 'P1'. p2 продолжает выполняться, но результат выполнения будет отброшен.

Резюме: Promise.all принимает массив объектов промисов и после того, как все они завершены, равномерно выполняет успех.;

Promise.race принимает массив из нескольких объектов обещаний и успешно выполняется до тех пор, пока один из них не завершится.

Измените приведенный выше пример, чтобы углубить ваше понимание двух:

var src1 = 'https://www.imooc.com/static/img/index/logo_new.png'
     var result1 = loadImg(src1)
     var src2 = 'https://img1.mukewang.com/545862fe00017c2602200220-100-100.jpg'
     var result2 = loadImg(src2)
     Promise.all([result1, result2]).then(function (datas) {
         console.log('all', datas[0])//<img src="https://www.imooc.com/static/img/index/logo_new.png">
         console.log('all', datas[1])//<img src="https://img1.mukewang.com/545862fe00017c2602200220-100-100.jpg">
     })
     Promise.race([result1, result2]).then(function (data) {
         console.log('race', data)//<img src="https://img1.mukewang.com/545862fe00017c2602200220-100-100.jpg">
     })

Если мы объединим обещания, мы сможем объединить множество асинхронных задач для параллельного и последовательного выполнения.

Promise.reject(причина): возвращает новыйpromiseобъект, используйте значение причины, чтобы напрямую изменить состояние наrejected.

const promise2 = new Promise((resolve, reject) => {
  reject('Failed');
});

const promise2 = Promise.reject('Failed');

Вышеупомянутые два способа написания эквивалентны.

Promise.resolve(value): возвращает новый объект обещания, который был разрешен. Подобно отклонению, следующие два способа написания эквивалентны.

const promise2 = new Promise((resolve, reject) => {
  resolve('Success');
});

const promise2 = Promise.resolve('Success');

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

catch Используйте этот метод для перехвата ошибок и их обработки.

3.Async/Await введение и использование

Введение

  • async/await — это новый способ написания асинхронного кода.Перезвонитеа такжеPromise.
  • async/await реализован на основе Promise, его нельзя использовать для обычных callback-функций.
  • async/await, как и Promises, неблокирует.
  • async/await делает асинхронный код похожим на синхронный код, где и происходит его волшебство.

грамматика

Используйте пример обещания и пример async/await, чтобы продемонстрировать два фрагмента кода:

promise

const makeRequest = () =>
  getJSON()
    .then(data => {
      console.log(data)
      return "done"
    })

makeRequest()

async/await

const makeRequest = async () => {
  console.log(await getJSON())
  return "done"
}

makeRequest()

У них есть некоторые тонкие различия:

  • Перед функцией стоит ключевое слово aync. Ключевое слово await можно использовать только внутри функций, определенных в aync. Асинхронная функция неявно возвращает обещание, а значение разрешения обещания — это значение, возвращаемое функцией. (значение reosolve в примере — это строка «done»)

  • Пункт 1 подразумевает, что мы не можем использовать await во внешнем коде, потому что он не находится внутри асинхронной функции.

    // нельзя использовать await во внешнем коде ждать makeRequest()

    // это произойдет makeRequest().Затем((результат) => { // код })

await getJSON() означает, что console.log будет ждать, пока обещание getJSON не будет успешно разрешено перед выполнением.

В чем преимущества async/await перед промисами

1. Краткость

Как видно из примера, использование Async/Await явно экономит много кода. Нам не нужно писать .then, нам не нужно писать анонимные функции для обработки значения разрешения Promise, нам не нужно определять избыточные переменные данных, и мы избегаем вложенного кода. Эти небольшие преимущества быстро складываются, что станет более очевидным в следующих примерах кода.

2. Обработка ошибок

Async/Await позволяет try/catch обрабатывать как синхронные, так и асинхронные ошибки. В приведенном ниже примере промиса try/catch не может обработать ошибку JSON.parse, потому что она находится в промисе. Нам нужно использовать .catch, поэтому код обработки ошибок очень избыточен. И в нашем реальном производстве код будет более сложным.

const makeRequest = () => {
  try {
    getJSON()
      .then(result => {
        // JSON.parse可能会出错
        const data = JSON.parse(result)
        console.log(data)
      })
      // 取消注释,处理异步代码的错误
      // .catch((err) => {
      //   console.log(err)
      // })
  } catch (err) {
    console.log(err)
  }
}

С помощью async/await catch может обрабатывать ошибки JSON.parse.

const makeRequest = async () => {
  try {
    // this parse may fail
    const data = JSON.parse(await getJSON())
    console.log(data)
  } catch (err) {
    console.log(err)
  }
}

3. Условные операторы

В следующем примере вам нужно получить данные, а затем решить, возвращаться ли напрямую или продолжать получать дополнительные данные в соответствии с возвращенными данными.

const makeRequest = () => {
  return getJSON()
    .then(data => {
      if (data.needsAnotherRequest) {
        return makeAnotherRequest(data)
          .then(moreData => {
            console.log(moreData)
            return moreData
          })
      } else {
        console.log(data)
        return data
      }
    })
}

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

Приведенный выше код, написанный с использованием async/await, может значительно улучшить читабельность:

const makeRequest = async () => {
  const data = await getJSON()
  if (data.needsAnotherRequest) {
    const moreData = await makeAnotherRequest(data);
    console.log(moreData)
    return moreData
  } else {
    console.log(data)
    return data    
  }
}

4. Промежуточное значение

Вы, вероятно, сталкивались со сценарием, в котором вызывается promise1, вызывается promise2 с результатом, возвращаемым promise1, а promise3 вызывается с результатом обоих. Ваш код, скорее всего, будет выглядеть так:

const makeRequest = () => {
  return promise1()
    .then(value1 => {
      return promise2(value1)
        .then(value2 => {        
          return promise3(value1, value2)
        })
    })
}

Если промису3 не нужно значение1, можно легко сгладить вложенность промисов. Если вы терпеть не можете вложенность, вы можете избежать глубокой вложенности, поставив значения 1 и 2 в Promise.all:

const makeRequest = () => {
  return promise1()
    .then(value1 => {
      return Promise.all([value1, promise2(value1)])
    })
    .then(([value1, value2]) => {      
      return promise3(value1, value2)
    })
}

Этот подход жертвует семантикой ради удобочитаемости. Нет никакой причины помещать значение1 и значение2 в массив, кроме как избежать вложенности.

С async/await код становится невероятно простым и интуитивно понятным.

const makeRequest = async () => {
  const value1 = await promise1()
  const value2 = await promise2(value1)
  return promise3(value1, value2)
}

5. Стек ошибок

Следующий пример вызывает несколько промисов, предполагая, что где-то в цепочке промисов возникает ошибка:

const makeRequest = () => {
  return callAPromise()
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => {
      throw new Error("oops");
    })
}

makeRequest()
  .catch(err => {
    console.log(err);
    // output
    // Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)
  })

Стек ошибок, возвращенный в цепочке промисов, не дает сведений о том, где произошла ошибка. Что еще хуже, это вводит нас в заблуждение: единственная функция в стеке ошибок называется callAPromise, но она не имеет ничего общего с ошибками. (имена файлов и номера строк по-прежнему полезны).

Однако стек ошибок в async/await будет указывать на функцию, в которой произошла ошибка:

const makeRequest = async () => {
  await callAPromise()
  await callAPromise()
  await callAPromise()
  await callAPromise()
  await callAPromise()
  throw new Error("oops");
}

makeRequest()
  .catch(err => {
    console.log(err);
    // output
    // Error: oops at makeRequest (index.js:7:9)
  })

В среде разработки это не является большим преимуществом. Однако это будет очень полезно при анализе журнала ошибок производственной среды. В этот момент лучше знать, что ошибка произошла в makeRequest, чем знать, что ошибка произошла в цепочке then.

6. Отладка

И последнее, но не менее важное: async/await может упростить отладку кода. Отладка промисов — это боль по двум причинам:

  • Вы не можете устанавливать точки останова в стрелочных функциях, которые возвращают выражения

    const markRequest = () => { return callAPromise () .then (() => callAPromise()) .then (() => callAPromise()) .then (() => callAPromise()) .then (() => callAPromise())

    }

  • Если вы установите точку останова в блоке кода .then с помощью сочетания клавиш Step Over, отладчик не перейдет к следующему .then, потому что он будет выполнять только асинхронный код. С await/async вам больше не нужно столько стрелочных функций, поэтому вы можете пропускать операторы await, как при отладке синхронного кода.

    const markRequest = async () => {
        await callAPromise()
        await callAPromise()
        await callAPromise()
        await callAPromise()
        await callAPromise()
    }
    

Суммировать

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