<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://www.w3.org/Bugs/Public/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4"
          urlbase="https://www.w3.org/Bugs/Public/"
          
          maintainer="sysbot+bugzilla@w3.org"
>

    <bug>
          <bug_id>25472</bug_id>
          
          <creation_ts>2014-04-25 23:49:23 +0000</creation_ts>
          <short_desc>autocomplete: return a promise for requestAutocomplete()</short_desc>
          <delta_ts>2016-06-16 15:50:59 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WHATWG</product>
          <component>HTML</component>
          <version>unspecified</version>
          <rep_platform>Other</rep_platform>
          <op_sys>other</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>WONTFIX</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>P3</priority>
          <bug_severity>enhancement</bug_severity>
          <target_milestone>2017 Q1</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Ian &apos;Hixie&apos; Hickson">ian</reporter>
          <assigned_to name="Ian &apos;Hixie&apos; Hickson">ian</assigned_to>
          <cc>annevk</cc>
    
    <cc>bnicholson</cc>
    
    <cc>d</cc>
    
    <cc>dbeam</cc>
    
    <cc>esprehn</cc>
    
    <cc>estade</cc>
    
    <cc>ian</cc>
    
    <cc>MattN+w3</cc>
    
    <cc>mike</cc>
          
          <qa_contact>contributor</qa_contact>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>104481</commentid>
    <comment_count>0</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-04-25 23:49:23 +0000</bug_when>
    <thetext></thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>105199</commentid>
    <comment_count>1</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-05-06 16:23:31 +0000</bug_when>
    <thetext>Before I can do this, I need a concrete proposal for how exactly it should work. I&apos;m not familiar enough with how promises are supposed to work to design it.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111456</commentid>
    <comment_count>2</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-12 18:29:22 +0000</bug_when>
    <thetext>I&apos;ve learnt enough about promises that I can probably make a proposal here. The question now is just: does anyone want to implement this, or is the event API sufficient?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111459</commentid>
    <comment_count>3</comment_count>
    <who name="Brian Nicholson">bnicholson</who>
    <bug_when>2014-09-12 18:49:12 +0000</bug_when>
    <thetext>I would be happy to implement this for Firefox.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111462</commentid>
    <comment_count>4</comment_count>
    <who name="Dan Beam">dbeam</who>
    <bug_when>2014-09-12 21:06:00 +0000</bug_when>
    <thetext>Ian or Brian: could you write an example code snippet of how web authors would use requestAutocomplete() with a Promise (so I can visualize it)?

I&apos;ve previously looked into this; see [1] and [2] for more context.

I prototyped my proposal [3] five months ago and would be happy to resume work on this if we can agree on an API (that was the previous blocker).

[1] http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2014-April/254142.html
[2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=25457
[3] https://codereview.chromium.org/228783007/</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111613</commentid>
    <comment_count>5</comment_count>
    <who name="Brian Nicholson">bnicholson</who>
    <bug_when>2014-09-16 18:52:39 +0000</bug_when>
    <thetext>I initially anticipated this API to resolve only on success and reject for all failures, including user cancellation. Intuitively, that seems more straightforward to me as it allows the reject handler to iterate through all errors versus splitting different kinds of errors between resolve and reject.

I agree, though, that user cancellation isn&apos;t an exceptional event, so that muddies things a bit. Is there an established precedent for cancellation (and other non-exceptional failures) from other APIs using promises?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111686</commentid>
    <comment_count>6</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-17 15:32:51 +0000</bug_when>
    <thetext>I would just have anything that fires &apos;autocomplete&apos; now also result in the promise being resolved with the form as its value, and anything that results in &apos;autocompleteerror&apos; now result in the promise being rejected with the reason string as its value. (I wouldn&apos;t reject with an exception since failure here is not exceptional.)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111688</commentid>
    <comment_count>7</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-17 15:40:14 +0000</bug_when>
    <thetext>(see also my comment on bug 25457 comment 17)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111689</commentid>
    <comment_count>8</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-09-17 15:40:28 +0000</bug_when>
    <thetext>That sound wrong. We&apos;ll get declarative syntax for promises. At that point they&apos;re the same as a function call. Their either return a value or throw. So that&apos;s how we should model this. E.g. how would you model this assuming the operation was blocking:

  var r
  try {
    r = obj.requestAutoComplete()
  } catch(e) {
    r = e
  }
  console.log(r)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111711</commentid>
    <comment_count>9</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-17 20:06:31 +0000</bug_when>
    <thetext>If it was blocking I would model it as:

   if (obj.requestAutocomplete()) {
     // success
   } else {
     switch (obj.rejectReason) {
       // ...
     }
   }

...or some such (in a sane language with pass-by-reference arguments, I would just have an &quot;out&quot; argument where the reject reason would put stuffed).

There&apos;s no exceptions here. The user canceling the dialog, for instance, isn&apos;t an exceptional situation. Modeling it with exceptions would make no sense IMHO.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111872</commentid>
    <comment_count>10</comment_count>
    <who name="Dan Beam">dbeam</who>
    <bug_when>2014-09-20 00:24:44 +0000</bug_when>
    <thetext>Cancel will probably happen more than success (for now, maybe always?) and therefore would probably never throw (nor reject).


This means that if rAc returns a Promise:

 ↪ If any other error would throw/reject:
  ↪ authors will have to handle failures in both resolution/rejection

 ↪ If no errors would throw/reject:
  ↪ the returned Promise is a fancy callback (and rejection logic is superfluous)


If rAc was changed to throw when invoked:
- from an insecure page
- from within &lt;iframe&gt;
- without a user gesture

the sync code would look possibly like this:

  try {
    form.requestAutocomplete();
    // determine whether user cancelled or filled inputs are valid here
    // maybe by returning something or adding an attribute to the form?
  } catch (e) {
    // figure out what failed (maybe e.reason tells you?)
  }

and the Promise version would be:

  form.requestAutocomplete().then(function() {
    // differentiate success from cancel/invalid somehow
  }, function() {
    // figure out what failed (maybe arguments[0] is &apos;disabled&apos;?)
  });


If rAc never throws, I&apos;d imagine the sync code looking like this:

  // this could easily be changed to a boolean like Ian&apos;s example
  var result = form.requestAutocomplete();
  if (result == &apos;success&apos;) {
    // &apos;success&apos; is new and more explicit than an empty failure reason
  } else {
    // determine what happened (is result &apos;cancel&apos;, &apos;invalid&apos;, or &apos;disabled&apos;?)
  }

and Promise-y would be:

  form.requestAutocomplete().then(function() {
    // maybe arguments[0] is &apos;success&apos;, &apos;cancel&apos;, &apos;invalid&apos;, or &apos;disabled&apos;?
  });


The second alternative is better, IMO, but I&apos;d prefer more flexibility with what is passed to the resolver (if we ever need to provide more than just a reason).


tl;dr - I&apos;d still use the event-based API on my site as rAc&apos;s majority case is a valid failure (cancel).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111918</commentid>
    <comment_count>11</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-22 16:26:26 +0000</bug_when>
    <thetext>Maybe we should just not use a promise here.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>111957</commentid>
    <comment_count>12</comment_count>
    <who name="Domenic Denicola">d</who>
    <bug_when>2014-09-22 17:58:46 +0000</bug_when>
    <thetext>Promises are perfect for requestAutocomplete. I find it baffling that this is a point of contention at all. It does seem to stem from some misunderstanding of promises as &quot;fancy callbacks&quot; or not understanding what they give you over events.

In terms of design: exceptional cases (i.e. cases which the author often does not want to write code to handle, but instead wants to allow to bubble up through the async call stack) should reject. So rejecting on insecure page/within &lt;iframe&gt;/without user gesture sounds reasonable to me.

Concrete design as requested in comment #1:

- requestAutocomplete returns a promise for a boolean. The promise is resolved with true if the autocomplete succeeds, and false if the user cancels. If the autocomplete fails for another reason, the promise is rejected.
- For the rejection, either:
  - AutocompleteError subclasses DOMException with reason \in { &quot;insecure origin&quot;, &quot;within iframe&quot;, &quot;no user gesture&quot;, &quot;invalid form&quot; }.
  - You mint several new .name values for DOMException corresponding to each of those cases.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112038</commentid>
    <comment_count>13</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-23 18:21:40 +0000</bug_when>
    <thetext>If you do that then you end up with error-checking logic in both paths. That doesn&apos;t make much sense — it would make the current event API more usable.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112040</commentid>
    <comment_count>14</comment_count>
    <who name="Domenic Denicola">d</who>
    <bug_when>2014-09-23 18:27:09 +0000</bug_when>
    <thetext>(In reply to Ian &apos;Hixie&apos; Hickson from comment #13)
&gt; If you do that then you end up with error-checking logic in both paths. That
&gt; doesn&apos;t make much sense — it would make the current event API more usable.

I attempted to divide the &quot;errors&quot; into &quot;things you want to handle&quot; (cancel) and &quot;things you don&apos;t want to handle but instead let bubble up through the async scope chain&quot; (environmental factors outside your control). Thus you would not even include the error-checking logic in most cases, instead letting it bubble.

Do you think my division is incorrect?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112084</commentid>
    <comment_count>15</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-24 17:07:59 +0000</bug_when>
    <thetext>Why would you not want to handle the case of the browser not showing the dialog? That would leave your page unusable.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112140</commentid>
    <comment_count>16</comment_count>
    <who name="Evan Stade">estade</who>
    <bug_when>2014-09-24 21:51:38 +0000</bug_when>
    <thetext>&gt; Why would you not want to handle the case of the browser not showing the
&gt; dialog? That would leave your page unusable.

I agree you should handle the case of the browser not showing the dialog because it&apos;s spec&apos;d as &quot;the dialog may fail to show for any old reason&quot;. That said, Chrome aims to always show the dialog, although what exactly is inside the dialog may depend on user settings. Even if they&apos;ve disabled Autofill, for example, the dialog still appears; they just have to type in everything afresh and it won&apos;t be saved. Of course, the dialog may not appear on an http:// site, may not appear if you don&apos;t request the right kind of fields, etc., but that&apos;s a programming error as opposed to a result of a user setting or state.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112183</commentid>
    <comment_count>17</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-25 17:22:18 +0000</bug_when>
    <thetext>Since we allow the browser to decide what fields it supports, not showing it because the fields aren&apos;t supported it not caused by a programmatic error on the author&apos;s behalf.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112414</commentid>
    <comment_count>18</comment_count>
    <who name="Brian Nicholson">bnicholson</who>
    <bug_when>2014-09-29 20:45:02 +0000</bug_when>
    <thetext>(In reply to Ian &apos;Hixie&apos; Hickson from comment #15)
&gt; Why would you not want to handle the case of the browser not showing the
&gt; dialog? That would leave your page unusable.

I think that what Dominic was suggesting is that rather than having the rAc error checking intimately tied to requestAutocomplete() call, authors may want errors to bubble so they can be handled at a more general level. This is one of features that make promises so compelling to begin with: they can be used seamlessly with exceptions and other promise-based APIs.

Consider the following (using ES6 generators, allowing for linear asynchronous code):

function* handleCheckout() {
  try {
    // synchronous; may throw exception
    mySite.ensureCartNotEmpty();

    // async; rejects if items not in stock
    yield mySite.ensureItemsInStock();

    // async; rejects on error and returns false on cancel
    var success = yield form.requestAutocomplete();
    if (success) {
      form.submit();
    }
  } catch (e) {
    console.log(&quot;An error has occurred during checkout&quot;);
    if (e instanceof AutocompleteError) {
      mySite.showStandardForm();
    }
    mySite.sendErrorToServer(e);
  }
}</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112436</commentid>
    <comment_count>19</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-09-30 02:04:42 +0000</bug_when>
    <thetext>That could work...</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112542</commentid>
    <comment_count>20</comment_count>
    <who name="Dan Beam">dbeam</who>
    <bug_when>2014-10-02 00:15:47 +0000</bug_when>
    <thetext>Would we need to change requestAutocomplete to throw when it rejects (it doesn&apos;t currently)?  I assume comment 18 implies this, but just double-checking.

Because rAc can fail for reasons unknown to the page (decided by the user agent[1]), all rAc calls would need a try {...} catch(e) {...} wrapper.  This is kind of arduous...

Also relevant: http://lists.w3.org/Archives/Public/public-whatwg-archive/2014Oct/0011.html

[1] https://html.spec.whatwg.org/#dom-form-requestautocomplete step #2
(i.e. &quot;the user agent does not support this form&apos;s fields&quot;, &quot;the user has disabled this feature for this form&apos;s node document&apos;s origin&quot;)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112544</commentid>
    <comment_count>21</comment_count>
    <who name="Matthew Noorenberghe">MattN+w3</who>
    <bug_when>2014-10-02 00:45:48 +0000</bug_when>
    <thetext>(In reply to Dan Beam from comment #20)
&gt; Would we need to change requestAutocomplete to throw when it rejects (it
&gt; doesn&apos;t currently)?  I assume comment 18 implies this, but just
&gt; double-checking.

I don&apos;t believe comment 18 implies this as my understanding is that a promise rejection gets converted into an exception when one uses yield on the promise.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112546</commentid>
    <comment_count>22</comment_count>
    <who name="Dan Beam">dbeam</who>
    <bug_when>2014-10-02 00:49:04 +0000</bug_when>
    <thetext>(In reply to Matthew Noorenberghe from comment #21)
&gt; (In reply to Dan Beam from comment #20)
&gt; &gt; Would we need to change requestAutocomplete to throw when it rejects (it
&gt; &gt; doesn&apos;t currently)?  I assume comment 18 implies this, but just
&gt; &gt; double-checking.
&gt; 
&gt; I don&apos;t believe comment 18 implies this as my understanding is that a
&gt; promise rejection gets converted into an exception when one uses yield on
&gt; the promise.

Right, I meant for the synchronous cases (e.g. http:, no user gesture, from frame, etc.).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112662</commentid>
    <comment_count>23</comment_count>
    <who name="Brian Nicholson">bnicholson</who>
    <bug_when>2014-10-03 20:25:18 +0000</bug_when>
    <thetext>(In reply to Dan Beam from comment #22)
&gt; Right, I meant for the synchronous cases (e.g. http:, no user gesture, from
&gt; frame, etc.).

Why does it matter if these are synchronous or asynchronous? If requestAutocomplete() returned a promise, it would be rejected in either case to indicate the error, and it should make no difference to clients using the promise.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112678</commentid>
    <comment_count>24</comment_count>
    <who name="Dan Beam">dbeam</who>
    <bug_when>2014-10-04 03:22:42 +0000</bug_when>
    <thetext>(In reply to Brian Nicholson from comment #23)
&gt; (In reply to Dan Beam from comment #22)
&gt; &gt; Right, I meant for the synchronous cases (e.g. http:, no user gesture, from
&gt; &gt; frame, etc.).
&gt; 
&gt; Why does it matter if these are synchronous or asynchronous? If
&gt; requestAutocomplete() returned a promise, it would be rejected in either
&gt; case to indicate the error, and it should make no difference to clients
&gt; using the promise.

I&apos;m talking about the Promise-less API.

As I understand it, Promise semantics are:
 - reject if the code would throw
 - otherwise resolve with what the code would return

Chrome&apos;s implementation knows enough to throw in some cases it&apos;d reject, e.g.,

  try {
    // if the page is insecure, not processing a user gesture, form.autocomplete == &quot;off&quot;, or in
    // a document fragment, throw right now as the promise will be rejected later.
    form.requestAutocomplete();
  } catch(e) {
    // examine e.reason
  }

I assume we *don&apos;t* want to do this, right?  Am I misunderstanding how Promise semantics?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112679</commentid>
    <comment_count>25</comment_count>
    <who name="Dan Beam">dbeam</who>
    <bug_when>2014-10-04 03:24:21 +0000</bug_when>
    <thetext>(In reply to Dan Beam from comment #24)
&gt; I assume we *don&apos;t* want to do this, right?  Am I misunderstanding how
&gt; Promise semantics?

misunderstanding Promise semantics**</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112685</commentid>
    <comment_count>26</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-10-04 07:32:47 +0000</bug_when>
    <thetext>Dan, you&apos;re correct. From the author of the promises specification: http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112809</commentid>
    <comment_count>27</comment_count>
    <who name="Brian Nicholson">bnicholson</who>
    <bug_when>2014-10-08 00:31:56 +0000</bug_when>
    <thetext>(In reply to Dan Beam from comment #24)
&gt; I&apos;m talking about the Promise-less API.

Apologize for the confusion earlier. Let&apos;s back up a bit...

By promise-less API, you&apos;re talking about the existing API, correct? As in, once this bug lands, the promise-less API will no longer exist, and since there&apos;s little value in changing the existing API in the interim, I assume your question is entirely academic?

Going on this assumption, I understand your argument as the following:
1) There is a 1:1 conversion between synchronous exceptions and promise rejections.
2) The existing API doesn&apos;t (and shouldn&apos;t) throw exceptions.
3) Therefore, we should not use promises.

My take: given an API with only synchronous failures, I do think that API should throw exceptions for exceptional situations. However, rAc also has asynchronous failures. There isn&apos;t a direct conversion from the existing API to promises because the existing API is partly async. I think an error callback was the right call for the sake of consistency; it&apos;s not that exceptions don&apos;t fit, but rather that we simply can&apos;t throw exceptions for async operations.

Of course, that&apos;s changing with the new generator syntax I used above, and why I feel promises are an improvement to the existing API.

(In reply to Anne from comment #26)
&gt; Dan, you&apos;re correct. From the author of the promises specification:
&gt; http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/

Note that Domenic, the author of that article, is the same person who proposed this new API back in comment 12 :)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>112927</commentid>
    <comment_count>28</comment_count>
    <who name="Domenic Denicola">d</who>
    <bug_when>2014-10-09 18:44:00 +0000</bug_when>
    <thetext>I think things got a little confused about sync vs. async. When we talked about &quot;if it was sync,&quot; that was meant as an analogy so that people got the right frame of mind for how to translate the API to promises. But somehow that got spun into saying that rAc should have sync behavior like throwing.

To be clear, it definitely should not: rAc should always reject and never throw. When a function becomes async (i.e. promise-returning), it switches from returning and throwing as a paradigm to fulfilling and rejecting its returned promise. So yeah, lack of user gesture etc. should reject, not throw.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>113161</commentid>
    <comment_count>29</comment_count>
    <who name="Ian &apos;Hixie&apos; Hickson">ian</who>
    <bug_when>2014-10-15 00:19:24 +0000</bug_when>
    <thetext>So the problem with comment 18&apos;s suggestion is it doesn&apos;t work when you combine promises. You can&apos;t take this promise, combine it with another promise for &quot;network is up again&quot;, and have it submit the form, because you don&apos;t know if the autocomplete promise in this scenario was canceled or not.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>125641</commentid>
    <comment_count>30</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2016-03-28 13:17:54 +0000</bug_when>
    <thetext>1. Is this still desired functionality?
2. Will the existence of cancelable promises influence the design?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>126785</commentid>
    <comment_count>31</comment_count>
    <who name="Domenic Denicola">d</who>
    <bug_when>2016-06-16 15:50:59 +0000</bug_when>
    <thetext>requestAutocomplete is gone</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>