【问题标题】:Creating a promise for web worker's onmessage event with nth number of REST calls使用第 n 个 REST 调用为 Web Worker 的 onmessage 事件创建一个 Promise
【发布时间】:2021-07-02 10:56:58
【问题描述】:

我正在使用网络工作者以递归方式获取网站信息,包括其子网站(第 n 个数字)。完成所有调用后,我想触发一个函数,该函数将格式化它接收到的数据(allSites 数组)。所以我认为将 Promise.all 与一个包含我所有已解决承诺的对象一起使用是一个好主意。

问题在于它不会等待所有已解决的承诺,因为它正在等待听取工作人员发布的消息。我无法定义长度,因为它可以是任意数量的网站 + 子网站。

奖励:我有一个已解决承诺的对象。我可以这样称呼某个决心吗?

keyName[index]() 

它说它不是一个函数,但我不应该这样称呼它吗?非常感谢任何帮助。

function getTreeData(cb) {
  let allSites = [];
  let baseUrl = "https://www.somewebsite.com/"
  let resolver = {};
  let rejecter = {};
  let workerUrl =
    "https://www.somewebsite.com/siteassets/worker.js";
  let myWorker = new Worker(workerUrl);

  function firstIteration() {
    return new Promise((resolve, reject) => {
      resolver[baseUrl] = resolve;
      rejecter[baseUrl] = reject;
      myWorker.postMessage({
        requestDigest: document.getElementById("__REQUESTDIGEST").value,
        qs1: "/_api/web/webinfos?$select=ServerRelativeUrl,Title",
        qs2:
          "/_api/Web/RoleAssignments?$expand=Member/Users,RoleDefinitionBindings",
        url: baseUrl,
      });
    });
  }
  firstIteration();

  //spawn a worker
  myWorker.onmessage = function (e) {
    allSites = allSites.concat([
      { pathname: e.data.url, groups: e.data.permissions },
    ]);

    e.data.sites.forEach(function (props) {
      return new Promise((resolve, reject) => {
        myWorker.postMessage({
          requestDigest: document.getElementById("__REQUESTDIGEST").value,
          qs1: "/_api/web/webinfos?$select=ServerRelativeUrl,Title",
          qs2:
            "/_api/Web/RoleAssignments?$expand=Member/Users,RoleDefinitionBindings",
          url: "www.somewebsite.com" + props.url,
        });
        resolver[props.url] = resolve;
        rejecter[props.url] = reject;
      });
    });
    resolver[e.data.url](); //it says that it is not a function
  };

  myWorker.onerror = function (e) {
    rejecter[e.data.url]();
  };
  
  //After my first inital promises resovles resolve the rest (checks object of resolves)
  resolver[baseUrl]().then(() => {
    Promise.all(Object.values(resolver)).then(() => {
      reduceData(cb, allSites);
    });
  });
}

虽然它工作正常,但这里是网络工作者的代码。 (worker.js)

function formatSites(props) {
  return {
    url: "www.someSite.com",
  };
}

function formatSitesInfo(props) {
  //get all info of the site or subsite
  var accessArr = props.RoleDefinitionBindings.results
    .reduce(function (r, a) {
      return r.concat([a.Name]);
    }, [])
    .sort()
    .join(", ");
  return {
    access: accessArr,
    isGroup: props.Member.hasOwnProperty("AllowRequestToJoinLeave")
      ? true
      : false,
    name: props.Member.Title,
    members: (props.Member.Users?.results || []).map(function (member) {
      return {
        access: accessArr,
        email: member.Email,
        groupName: props.Member.Title,
        id: member.Id,
        isAdmin: member.IsSiteAdmin,
        title: member.Title,
      };
    }),
  };
}

function _getRequest(props) {
  return new Promise(function (resolve, reject) {
    fetch(props.url + props.qs, {
      method: "GET",
      headers: {
        Accept: "application/json; odata=verbose",
        "Content-type": "application/json; odata=verbose",
        "X-RequestDigest": props.requestDigest,
      },
    })
      .then(function (resp) {
        return resp.json();
      })
      .then(resolve)
      .catch(reject);
  });
}

self.addEventListener("message", function (e) {
  if (!e.data.data) {
    var promise1 = _getRequest(Object.assign(e.data, { qs: e.data.qs1 }));
    var promise2 = _getRequest(Object.assign(e.data, { qs: e.data.qs2 }));

    Promise.all([promise1, promise2]).then(function ([data1, data2]) {
      self.postMessage({
        info: data2.d.results.map(formatSitesInfo),
        sites: data1.d.results.map(formatSites),
        url: e.data.url,
      });
    });
  }
});

【问题讨论】:

  • 这里有几个错误,Promise.all 返回一个承诺,你没有对这个承诺做任何事情,所以它是一个 NULL OP。第二个fetch 返回一个promise,但你不要在_getRequest 中返回它,无论如何在这里使用Promise 构造函数是一种反模式。
  • 是的,它应该返回一个承诺。在进行第一次调用后,Promise.all() 将通过解析器 obj 的值。解析器 obj 看起来像这样 resolver = { site1: f(), site2; f()} 值等于解析。所以发现所有的值都是0“解决”它应该去下一个函数; thenable 是我的格式化函数
  • 对于 fetch 承诺:因为它在 promise.all 中,所以它要么显示解决要么拒绝。我没有问题(不好的做法),但你应该可以这样写。
  • 现在阅读构造函数反模式
  • 据我所知,您从未将resolver[e.data.url] 设置为任何内容。你为一些整数设置了resolver[e.data.sites[i].url] i,你设置了resolver[baseUrl] 你知道e.data.url 是这些值之一吗?

标签: javascript rest recursion promise web-worker


【解决方案1】:

如果有另一个呼叫工人(另一个子站点被发现有子站点),我最终会重置计时器。如果计时器停止,则意味着我们已经到达站点子节点的末尾。然后它进入下一个功能。会有一点延迟,但这是我可以忍受的。

【讨论】:

    猜你喜欢
    • 2019-08-14
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    • 2014-02-08
    • 2014-05-31
    • 2019-10-21
    • 1970-01-01
    相关资源
    最近更新 更多