Zapier触发器中的顺序承诺

时间:2018-03-27 13:23:01

标签: javascript promise zapier

我有一个从Web服务检索数据的Zapier触发器(app)。 Web服务以500个项目为单位返回数据,每个项目包含一个UNIX时间戳,Web服务参数('since')指定要检索的数据块的开始时间。

为了使其工作,我需要按顺序检索数据块,在前一个块中检索的数据允许我找到下一个Web服务调用的“since”值。

我目前使用的代码:

const fetchItems = (z, bundle, since) => {

    return z.request({

        url: URL_PATH + ':' + URL_PORT + '/v1/items',
        params: {
            since: since
        }

    }).then(( response) => {

        if (response.status === 401) {
            throw new Error('The authentication has expired.');
        } else if (response.status !== 200){
            throw new Error('Status ' + response.status + ' returned.');
        }

        return response.json;
    });
};

const processItems = (z, bundle) => {

    var jsonAll = [];
    var since = 0;
    var jsonLength = ITEM_BLOCK_SIZE;

    return (function loop(i) {

        if (jsonLength === ITEM_BLOCK_SIZE) {

            new Promise((resolve, reject) => {

                fetchTransactions(z, bundle, since).then((json) => {

                    since = json[json.length - 1].modified;
                    jsonLength = json.length;

                    for (j = 0; j < json.length; j++) {

                        jsonAll.push( json[j]);
                    }

                    resolve();
                });

            }).then(loop.bind(null, jsonLength));

        } else {

            return jsonAll;
        }

    })(0);
}

module.exports = {
    ...
    operation: {
        ...
        perform: processItems,
        ...
    }
}; 

我遇到的问题是,当我运行此代码时,Zapier会返回以下错误:结果必须是数组,得到:undefined,()

fetchItems()函数工作正常,它返回指定'since'值的数据块。

我在使用承诺方面经验有限,所以我们将不胜感激任何帮助。

1 个答案:

答案 0 :(得分:2)

我花了一些时间来解开processItems的意图,但过了一会儿我就掌握了逻辑。我真的很欣赏IIFE loop逻辑的简单之美,所以在我的版本中保留了它,但你混淆了一些关于同步和异步代码如何工作的假设(这可能是由于对promises的不熟悉)。

const processItems = (z, bundle) => {
  const jsonAll = [];
  let since = 0;

  return new Promise((resolve, reject) => {
    (function loop() {
      console.log("inLoop");
      fetchTransactions(z, bundle, since)
        .then(json => {
          const jsonLength = json.length;
          since = json[json.length - 1].modified;

          jsonAll.push(...json);

          if (jsonLength === ITEM_BLOCK_SIZE) {
            loop(jsonLength);
          } else {
            resolve(jsonAll);
          }
        })
        .catch(reject);
    })();
  });
};

// Testdriver (proves it works)
let callCount = 0;
const ITEM_BLOCK_SIZE = 10;
function fetchTransactions() {
  return new Promise(resolve => {
    if (callCount === 5) return resolve([{ modified: 100 }]);
    const list = [];

    for (let i = 0; i < ITEM_BLOCK_SIZE; i++) list.push({ modified: 42 });
    callCount++;

    resolve(list);
  });
}


processItems({},{}).then(results =>
  console.log(
    "results are correct?",
    results.length === 5 * ITEM_BLOCK_SIZE + 1
  )
);

整个函数是 async 方法,而代码中的任何return语句当然都是同步。这就是它返回undefined的原因;函数体执行后很久就会返回返回的值!

这就是Promise闪耀的地方。您可以从方法中返回Promise,然后等待稍后完成的承诺。这就是失败的原因:你基本上需要在resolve函数内返回一个loop d的Promise。

所以我补充说,删除了我认为是一些不必要的Promise创建,并将一些全局状态转移到了本地状态。