多个步骤来处理数据,这是JS/Angular的好模式

Multiple steps to process data, what's good pattern for JS/Angular?

本文关键字:JS Angular 模式 这是 数据 处理      更新时间:2023-09-26

假设我们有几个步骤来处理数据。首先我们下载它,然后我们做其他事情,以此类推很多次。c#中的代码看起来像几行——每一步一行。

据我所知,在JS/Angular中,它看起来像这样:

function prepateAndGo() {
    loadData()
        .$promise.then((loadedData) => {
            prepareData(loadedData).$promise().then((preparedData) => {
           
                preprocessData(preparedData).$promise().then((preprocessedData) => {
                    andDoSmthElse(preprocessedData).$promise().then((andDoSmthElseData) => {
                        makeupData(andDoSmthElseData).$promise().then((makeupedData) => {
                            Console.log('finally, everything is loaded and processed, lets go');
                        });
                    });
                });
            });
        });
}

难道没有更漂亮的图案吗?对付意大利面常见的解决办法是什么?

您需要做的是创建返回承诺的实用程序函数。例如:

function prepareData(data){
    // do something with data and return a promise
    return $q.when(data);        
}

那么你可以很好地链接承诺。例如:

loadData()
    .then(prepareData)
    .then(preprocessData)
    .then(andDoSmthElse)
    .then(makeupData)
    .then(function(madeData){
        Console.log('finally, everything is loaded and processed, lets go');
    });

注意:代码是我的头,但应该让你开始

你听说过承诺链吗?

action1()
    .$promise.then((result2) => action2(result2))
    .$promise.then((result3) => action3(result3))
    .$promise.then((result4) => action4(result4))
    .$promise.then((result5) => action5(result5))
    .$promise.then((finalResult) => console.log('Finally got it.'))

由于每个回调函数本身都返回承诺,因此可以将.then()调用链接起来,如下所示:

function prepateAndGo() {
    loadData().$promise()
        .then(loadedData => prepareData(loadedData).$promise())
        .then(preparedData => preprocessData(preparedData).$promise())
        .then(preprocessedData => andDoSmthElse(preprocessedData).$promise())
        .then(andDoSmthElseData => makeupData(andDoSmthElseData).$promise())
        .then(makeupedData => {
            Console.log('finally, everything is loaded and processed, lets go');
         });
}

另外,正如Matt Way在他的回答中提到的,如果你改变你的API直接返回承诺,你可以完全摆脱箭头函数。

使这些链更具可读性的一种简单方法是将一些逻辑移动到单独的函数中。所以:

function prepareAndGo() {
  loadData()
    .then(processData)
    .then(doSomethingElse)
    .then(whatever)
    .catch(err => console.log(err))
}
function processData(data) {
  ...
  return Promise.resolve(stuff)
}
function doSomethingElse(data) {
  ...
  return Promise.resolve(stuff)
}
function whatever(data) {
  ...
  return Promise.resolve(stuff)
}

一个稍微更先进的方法是使用async/await模式,您可以在这里了解更多。目前在没有转译器的情况下使用async/await是不可能的,因为缺乏支持(但很快就会改变!)。

然而,你现在可以通过生成器利用这种模式,这是javascript ES2015规范中引入的新特性。承诺库Bluebird提供了一个名为coroutine的方法,它将生成器函数包装起来,使它们像async函数一样工作。下面是一个例子:

var Promise = require("bluebird")
let loadData = Promise.coroutine(function* (data) {
  let preparedData       = yield prepareData(data)
  let preprocessedData   = yield preprocessData(preparedData)
  let andDoSmthElseData  = yield andDoSmthElse(preprocessedData)
  let madeUpData         = yield makeupData(andDoSmthElseData)
  console.log('Everything is loaded and processed!')
  return madeUpData
})