【问题标题】:Promise syntax / alternative [duplicate]承诺语法/替代[重复]
【发布时间】:2016-06-07 07:39:04
【问题描述】:

我希望返回一个以后会自行解决的 Promise,但我的语法似乎无效,我很好奇有什么更好的实现方式。为什么 Promise 构造函数需要执行器?

promise = new Promise() 无效,因为我需要提供一个函数

function getDetails (someHash) {
    var url = "http://somewebsite.com/" + someHash,
        promise = new Promise();

     makeAjaxRequest(url, function (response) {
         promise.resolve(response.data);
     });

     setTimeout(function () {
         promise.reject("timeout");
     }, 500);

     return promise;
}

function makeAjaxRequest (url, callback) {
    var someResponse = {data: "some data"};

    setTimeout(function () {
        callback(someResponse);
    }, 200);
}

有没有更好的方法来实现这个功能?

【问题讨论】:

  • 第一function 行末尾的{} 是什么?
  • 这看起来像你的语法错误。
  • 我不知道为什么这被否决了,但在我看来这是一个很好的问题。
  • 你为什么不直接使用一个执行器来让你的代码工作?
  • @BenjaminGruenbaum:第一个问题似乎是您刚刚回答的stackoverflow.com/questions/37651780/… 的欺骗,第二个问题似乎是某种RTFM

标签: javascript asynchronous promise


【解决方案1】:

注意:如果要将回调 API 转换为 Promise,请参阅 this question

让我们从一开始就应该说的话开始。 不需要执行器来设计 Promise。 完全可以设计一个 Promise 实现来做类似的事情:

let {promise, resolve, reject} = Promise.get();

如果你保证不告诉任何人,我什至会告诉你一个小秘密 - 这个 API 甚至存在于规范的前一个迭代中,实际上甚至在 Chrome 中仍然有效:

let {promise, resolve, reject} = Promise.defer();

但是,它正在被删除。

那么,为什么我需要传递一个执行者呢?

just answered your other question 关于为什么 executor 是一个有趣的设计。它是安全的,可以让您处理有趣的事情。

我还能获得 resolve、reject 函数吗?我需要那些

根据我的经验,大多数时候我需要解决/拒绝我并不实际上需要它们。也就是说 - 实际上我确实需要他们几次。

说明符认识到这一点,因此执行器函数总是同步运行。你可以得到.defer 接口,它不是默认的:

function defer() {
    let resolve, reject, promise = new Promise((res, rej) => {
      [resolve, reject] = [res, rej];
    });
    return {resolve, reject, promise};
}

再次重申,这通常不是您想做的事情,但 完全有可能您有一个合理的用例,这就是为什么它不是默认的但完全可能的原因.

你的实际代码

我会从实现诸如超时和请求之类的东西作为原语开始,然后组合函数和链式承诺:

function delay(ms) {
  return new Promise(r => setTimeout(r, ms));
}
function timeout(promise, ms) {
   return Promise.race([
      promise,
      delay(ms).then(x => { throw new Error("timeout"); })
   ]);
}
function ajax(url) { // note browsers do this natively with `fetch` today
   return new Promise((resolve, reject) => { // handle errors!
      makeAjaxRequest(url, (result) => {
          // if(result.isFailure) reject(...);
          if(result.status >= 400) reject(new Error(result.status));
          else resolve(result.data);
      });
   });
}

现在,当我们承诺最低级别的 API 表面时,我们可以非常声明式地编写上述代码:

function getDetails (someHash) {
    var ajax = makeAjaxRequest("http://somewebsite.com/" + someHash);
    return timeout(ajax, 500);
}

【讨论】:

  • 我认为您的 defer 函数存在语法错误,因为前两个 const 变量缺少初始化程序。
  • 请注意,我从未发现需要类似延迟的模式但我无法使用 Promise 构造函数的情况。并且deferred.reject 是完全没有必要的,因为您可以随时使用resolve(Promise.reject(…)),这进一步简化了您需要将解析器存储在某处的大多数情况。
  • @Bergi 基本上,当您想要持有一个承诺但没有实际开始操作但更改默认语义时,该模式很有用 - 例如考虑一个图像标签,我可能想要一个 .loaded 承诺这在加载图像时实现,但如果图像未附加到 DOM,我可能不想实际加载图像。我需要在图像下载开始之前提供承诺。 (我当然可以通过另一个attached 承诺来解决这个问题,并将其加载到then,但是我将如何存储attached?)
  • 我的意思是一个模式,我需要一个deferred 对象,它同时拥有承诺和解析能力。当然,在稍后调用之前将resolve 存储在其他地方有时很有用,但我总是直接使用Promise 构造函数来做到这一点。关于您的示例,您实际上可以简单地创建图像对象并将resolve/reject 安装为onload/onerror 处理程序,然后通过设置src 开始加载任何内容 - 然后在您使用时执行此操作附上图片。
  • @Bergi 我的意思是 - 如果你是图像的实现者,而不是作为承诺者。
【解决方案2】:

您需要将一个函数传递给Promise 构造函数(more info),该构造函数将被调用以提供resolvereject 函数:

function getDetails (someHash) {
  var url = "http://somewebsite.com/" + someHash;

  return new Promise(function(resolve, reject) {
    makeAjaxRequest(url, function(err, response) {
      if (err)
        reject(err);
      else
        resolve(response.data);
    });

    setTimeout(function () {
      reject("timeout");
    }, 500);
  });
}

function makeAjaxRequest (url, callback) {
  var someResponse = {data: "some data"};

  setTimeout(function () {
    callback(null, someResponse);
  }, 200);
}

我还冒昧地让 makeAjaxRequest 使用传递错误作为第一个参数的标准约定(因为我假设在某些时候您想用实际的 AJAX 请求替换 setTimeout())。

【讨论】:

  • 他们不应该强制使用格式来解决或拒绝我自己的承诺
  • @neaumusic “他们”是谁?
  • 我想,他/她不喜欢这个规范。比deferred anti pattern
  • 谁设计了 Promise 规范,W3?
  • @neaumusic 所以你想实现你自己的 Promise 实现?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-03
  • 1970-01-01
  • 2015-08-06
  • 1970-01-01
  • 2018-02-01
  • 2014-12-19
  • 2015-02-08
相关资源
最近更新 更多