如何向 JavaScript 函数提供 XMLHttpRequest 承诺

How to provide an XMLHttpRequest promise to a JavaScript function

使用 https://www.npmjs.com/package/bootstrap-4-autocomplete 提供的自动完成插件,并进行以下工作:

$('#id').autocomplete({
    source: {'test1':1, 'test2':2, 'test1':3}
});

而不是本地 JSON,将需要创建一个 XMLHttpRequest 并且正在考虑以下内容,虽然我没有收到错误,但我也没有收到任何信息:

$('#id').autocomplete({
    source: function() {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                return JSON.parse(this.responseText);
            }
        };
        xhttp.open(method, url, true);
        xhttp.send();
    }
});

插件的作者remark不久前做了以下内容:

I don't have plans to directly invoke any url inside the lib. What you can do is set autocomplete to your textfield after your ajax call returns, which you can do with jQuery, like this:

$.ajax('myurl').then((data) => $('#myTextfield').autocomplete({ source: data }));

You don't have to worry about setting autocomplete to a field multiple times, it is supposed to work like this when you need to change the source.

尝试了一下,正如预期的那样,$.ajax() 在页面加载时发起了一个 XMLHttpRequest 请求,但当用户在搜索输入中输入一个字符时并不像预期的那样。

我怎样才能使 XMLHttpRequest 将数据源到插件中?我假设我应该使用一个承诺,但是,如果没有,仍然会感谢任何帮助。

谢谢

好吧,这就是插件应该如何工作的。它的核心是 createItems 函数,在 keyup 事件上调用 - 并负责用项目填充该下拉列表。这是它的关键部分(1.3.0 version):

function createItems(field: JQuery < HTMLElement > , opts: AutocompleteOptions) {
  const lookup = field.val() as string;

  // ...
  
  let count = 0;
  const keys = Object.keys(opts.source);
  for (let i = 0; i < keys.length; i++) {
    const key = keys[i];
    const object = opts.source[key];
    const item = {
      label: opts.label ? object[opts.label] : key,
      value: opts.value ? object[opts.value] : object,
    };
    if (item.label.toLowerCase().indexOf(lookup.toLowerCase()) >= 0) {
      items.append(createItem(lookup, item, opts));
      if (opts.maximumItems > 0 && ++count >= opts.maximumItems) {
        break;
      }
    }
  }

  // skipped the rest
}

如您所见,每次调用 createItems 时,它都会遍历 source 对象,查找所有包含查找字符串的项目。

所以所有的数据部分都应该在那里 - 并且可以同步处理。这就是插件的方式,这种方法有好有坏。

插件作者在这里建议的最好的事情(不违反插件的内容)是在调用自动​​完成之前使用 AJAX 预填充数据。这就是他在那条评论中所做的。


现在,这里可以做什么?有人可能认为将 createItems 转换为异步函数就足够了——例如,调用 source 如果它是一个函数并期望其结果是一个 Promise。排除进程中的查找循环似乎非常简单 - 只需获取 AJAX 调用的结果即可重新填充 source...

但不幸的是,这并不是那么简单:有几个注意事项需要注意。应该发生什么,例如,如果用户停止输入(触发第一个 AJAX 调用),然后再输入一些,然后再次停止(触发另一个 AJAX 调用)——但第一个实际上稍后到达?相应的错误困扰着我一直在使用的许多自动完成实现,可悲的是 - 如果您仅使用快速网络连接进行测试(更不用说仅在本地主机上),则重现并不容易。

这似乎只是作者决定不扩展该插件的原因之一。毕竟,它是为解决一项特定任务而构建的——而且它做得很好。因此,除非您想分叉它并将其重写为 'two strategies' 一个,否则我建议您考虑寻找其他地方。