[英]Leaving jQuery, wrote a simple ajax function, but chained methods will not wait
更新:添加了一个更简单的演示 jsfiddle, https://jsfiddle.net/47sfj3Lv/3/ 。
用更少的代码重现问题我试图摆脱 jQuery。
我的一些代码,用于填充一些表,有这样的代码
var hb = new hbLister(url: '#attributes.listURL#')
.getData(#url.page#, #url.per#)
.search(searchColumn, searchParam)
.render();
hbLister
会初始化一些东西getData
将执行 $.ajax 调用search
将console.log('filtering data')
并将搜索条件应用于 javascript objectrender
会将结果放在页面上。 重要的是,直到getData
中的 ajax 调用完成后, search
才会触发。
所以,现在我有了这个 ajax 构造函数。 我已经尽可能多地缩写了这段代码。
let ajax = function (options, hooks, headers) {
let that = this;
// enforce parameter types
// copy parameters to this.base
this.base = { options: options, hooks: hooks, headers: headers }
return function (url, options, data, hooks, headers) {
// enforce variable types
// merge options and hooks with their base.counterparts
headers = new Headers(Object.assign({}, that.base.headers, headers));
options.headers = headers;
return fetch(url, options)
.then(response => {
return response.json().then(json => {
console.log('processing');
if (response.ok) {
// it's omitted here but the Base functions are defined
// in the constructor parameters
hooks.successBase(json, response.status, response.headers);
hooks.success(response.json, response.status, response.headers)
} else {
hooks.failureBase(json, response.status, response.headers);
hooks.failure(response.json, response.status, response.headers)
}
})
});
}
}
这个想法是我可以说
let tableLister = new ajax()
然后getData
可以调用
tableLister = tableLister(hb.url, // url
{ type: "GET" }, // options
config.data, // data
{ success: successFn } // hooks, success being the callback
)
jQuery 调用将正确地给我然后processing
然后filtering data
。
这个 function 给了我filtering data
,一个错误,然后processing
,因为我似乎无法让链( .search(...).render()
)等待 ajax 调用完成。
这是 jsFiddle 上的一个独立示例, https://jsfiddle.net/47sfj3Lv/3/
我确信答案是异步等待,但我无法让它工作。
这是我尝试过的一个例子
return await (async function () {
console.log('fetching')
let fetcher = await fetch(url, options);
console.log('getting json');
return await fetcher.json().then((json) => {
console.log('have json, doing hooks');
if (fetcher.ok) {
let argXHR = { json: json}
hooks.successBase(argXHR, hooks.params);
hooks.success.forEach(v => v(argXHR, hooks.params));
hooks.afterSend(argXHR, hooks.params);
} else {
let argXHR = { json: json,}
hooks.failureBase(argXHR, hooks.params);
hooks.failure.forEach(v => v(argXHR, hooks.params));
hooks.afterError(argXHR, hooks.params);
}
console.log('finished hooks')
})
}())
而且无论我做什么,链条都会在等待结束之前继续。
我得到了 XMLHttpRequest 的代码来工作。 方法链( .getData().search(...).render()
)适用于此,因为这不允许 ajax function 在请求完成和执行回调之前返回。 **我仍然更愿意让.fetch()
工作。
let xhr = new XMLHttpRequest()
let urlParams = [];
Object.keys(data).forEach((v) => urlParams.push(v + '=' + encodeURIComponent(data[v])));
urlParams = urlParams.join('&')
xhr.open(options.method, options.url, false);
xhr.onreadystatechange = function(state) {
if (this.readyState == 4) {
let json = JSON.parse(xhr.responseText)
hooks.successBase(json, xhr.status, xhr.getResponseHeader);
hooks.success.forEach(v => v(json, xhr.status, xhr.getResponseHeader));
}
}
xhr.onerror = function() {
let json = JSON.parse(xhr.responseText)
hooks.failureBase(json, xhr.status, xhr.getResponseHeader);
hooks.failure.forEach(v => v(json, xhr.status, xhr.getResponseHeader));
}
for (h in headers) {
xhr.setRequestHeader(h, headers[h])
}
xhr.send(urlParams)
这对我来说很难理解,所以如果其他人有同样的问题,我想分享一下。
似乎异步方法会破坏方法链,这是没有办法的。 而且由于 fetch 是异步的,所以必须使用 await,为了使用 await,调用方法必须声明为 async。 因此方法链将被破坏。
调用方法链的方式必须改变。
在我的 OP 中,我将https://jsfiddle.net/47sfj3Lv/3/链接为同一问题的更简单版本。 StackOverflow 的 'fiddle' 出于安全原因有效地阻止了 'fetch',所以我需要使用 JSFiddle 进行演示。
这是相同代码的工作版本,使用then
及其工作方式/原因,以及稍短的版本,因为显然可以使用 fetch 指定 await 。
let obj = {};
// methods with fetch ideally should be specified async.
// async calls will automatically return a promise
obj.start = async () => {
console.log('start begins')
let retText = "",
fetcher = fetch('/', {}).then(response => response.text())
.then(text => {
console.log('fetch\'s last then')
retText = text
})
// fetcher has just been declared. It hasn't done anything yet.
console.log('fetch requested, returned length:', retText.length)
// this makes the fetcher and sequential then's happen
await fetcher;
console.log('await let fetch finish, returned length:', retText.length)
// Async functions will return a promise, but the return specified here
// will be passed to the next 'then'
return obj
}
obj.middle = () => {
console.log('middle called')
// Because this is not declared async, it behaves normally
return obj;
}
obj.end = () => {
console.log('end called')
// Because this is not declared async, it behaves normally
}
console.log('Method 1: ', obj.start()
// Because start is Async, it returns obj wrapped in a promise.
// As with any function, step may be named Anything you like
.then((step) => step.middle())
// Middle is not Async, but since it's wrapped in then
// it returns a promise
.then((step) => step.end())
)
// This is just wrapped in a timer so the two logs don't intermix with each other
// This is definitely the preferred method. Non-async chain-methods that return
// a reference to their object, do not need to wrapped in then().
setTimeout(function() {
console.log('------------------------')
console.log('Method 2: ', obj.start()
// Because start is Async, it returns obj wrapped in a promise.
// As with any function, step may be named Anything you like
.then((step) => step.middle().end())
)
}, 3000)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.