Return 通过 Web 组件 (MVC) 进行异步调用
Return asynchronous call through Web Components (MVC)
我正在使用纯 javascript 和 Web 组件构建一个应用程序。 我也想使用 MVC 模式,但现在我遇到了异步调用的问题模型。
我正在开发 meal-list
组件。数据来自 API 作为 JSON,格式如下:
[
{
id: 1,
name: "Burger",
},
]
我希望控制器从模型中获取数据并将其发送到视图。
meals.js(型号)
export default {
get all() {
const url = 'http://localhost:8080/meals';
let speisekarte = [];
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
}).then(res => {
return res.json()
}).then(data => {
// This prints the result I want to use, but I can't return
console.log(data);
// This does not work
speisekarte = data;
// This also does not work
return data;
});
// is undefined.
return speisekarte;
},
}
这就是我尝试从 API.
中获取数据的方式
餐-list.component.js(控制器)
import Template from './meal-list.template.js'
import Meal from '../../../../data/meal.js'
export default class MealListComponent extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'});
// Should send the Data from the model to the View
this.shadowRoot.innerHTML = Template.render(Meal.all);
}
}
if (!customElements.get('mp-meal-list')) {
customElements.define('mp-meal-list', MealListComponent);
}
餐-list.template.js(查看)
export default {
render(meals) {
return `${this.html(meals)}`;
},
html(meals) {
let content = `<h1>Speisekarte</h1>
<div class="container">`;
content += /* display the data from api with meals.forEach */
return content + '</div>';
},
}
正如我在评论中提到的,我在 return 将异步数据从模型发送到视图时遇到了问题。当我尝试 return data;
或者我尝试将数据保存到数组中时,它是未定义的。我也可以 return 整个 fetch()
方法,但是这个 return 是一个承诺,我认为控制器不应该处理这个承诺。
我已经阅读了 How do I return the response from an asynchronous call? 中的长线程,但我无法将其与我的案例联系起来。
既然您将 speisekarte
声明为一个数组,我希望它总是 return 作为一个空数组。当 fetch 执行并实现 promise 时,在上面的实现中总是来不及了。
您必须等待获取结果,您可以考虑多种选择:
- 要么提供对获取结果的回调
- 或者通过事件调度和侦听器通知您的应用程序您的数据已加载,因此它可以开始渲染
您的 link 已经对主题回调和 async/await 有了很好的回答,我不能说得比那里解释的更好了。
感谢 lotype 和 Danny '365CSI' Engelman,我为我的项目找到了完美的解决方案。我用自定义事件和 EventBus 解决了它:
meal.js(型号)
get meals() {
const url = 'http://localhost:8080/meals';
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
}).then(res => {
return res.json()
}).then(data => {
let ce = new CustomEvent(this.ESSEN_CHANGE_EVENT, {
detail: {
action: this.ESSEN_LOAD_ACTION,
meals: data,
}
});
EventBus.dispatchEvent(ce);
});
},
EventBus.js(摘自书籍:Web Components in Action)
export default {
/**
* add event listener
* @param type
* @param cb
* @returns {{type: *, callback: *}}
*/
addEventListener(type, cb) {
if (!this._listeners) {
this._listeners = [];
}
let listener = {type: type, callback: cb};
this._listeners.push(listener);
return listener;
},
/**
* trigger event
* @param ce
*/
dispatchEvent(ce) {
this._listeners.forEach(function (l) {
if (ce.type === l.type) {
l.callback.apply(this, [ce]);
}
});
}
}
现在,当数据准备就绪时,将向事件总线发送一个信号。 meal-list-component
正在等待事件,然后获取数据:
export default class MealListComponent extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = Template.render();
this.dom = Template.mapDOM(this.shadowRoot);
// Load Speisekarte on init
this.dom.meals.innerHTML = Template.renderMeals(MealData.all);
// Custom Eventlistener - always triggers when essen gets added, deleted, updated etc.
EventBus.addEventListener(EssenData.ESSEN_CHANGE_EVENT, e => {
this.onMealChange(e);
});
}
onMealChange(e) {
switch (e.detail.action) {
case EssenData.ESSEN_LOAD_ACTION:
this.dom.meals.innerHTML = Template.renderMEals(e.detail.meals);
break;
}
}
}
我正在使用纯 javascript 和 Web 组件构建一个应用程序。 我也想使用 MVC 模式,但现在我遇到了异步调用的问题模型。
我正在开发 meal-list
组件。数据来自 API 作为 JSON,格式如下:
[
{
id: 1,
name: "Burger",
},
]
我希望控制器从模型中获取数据并将其发送到视图。
meals.js(型号)
export default {
get all() {
const url = 'http://localhost:8080/meals';
let speisekarte = [];
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
}).then(res => {
return res.json()
}).then(data => {
// This prints the result I want to use, but I can't return
console.log(data);
// This does not work
speisekarte = data;
// This also does not work
return data;
});
// is undefined.
return speisekarte;
},
}
这就是我尝试从 API.
中获取数据的方式餐-list.component.js(控制器)
import Template from './meal-list.template.js'
import Meal from '../../../../data/meal.js'
export default class MealListComponent extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'});
// Should send the Data from the model to the View
this.shadowRoot.innerHTML = Template.render(Meal.all);
}
}
if (!customElements.get('mp-meal-list')) {
customElements.define('mp-meal-list', MealListComponent);
}
餐-list.template.js(查看)
export default {
render(meals) {
return `${this.html(meals)}`;
},
html(meals) {
let content = `<h1>Speisekarte</h1>
<div class="container">`;
content += /* display the data from api with meals.forEach */
return content + '</div>';
},
}
正如我在评论中提到的,我在 return 将异步数据从模型发送到视图时遇到了问题。当我尝试 return data;
或者我尝试将数据保存到数组中时,它是未定义的。我也可以 return 整个 fetch()
方法,但是这个 return 是一个承诺,我认为控制器不应该处理这个承诺。
我已经阅读了 How do I return the response from an asynchronous call? 中的长线程,但我无法将其与我的案例联系起来。
既然您将 speisekarte
声明为一个数组,我希望它总是 return 作为一个空数组。当 fetch 执行并实现 promise 时,在上面的实现中总是来不及了。
您必须等待获取结果,您可以考虑多种选择:
- 要么提供对获取结果的回调
- 或者通过事件调度和侦听器通知您的应用程序您的数据已加载,因此它可以开始渲染
您的 link 已经对主题回调和 async/await 有了很好的回答,我不能说得比那里解释的更好了。
感谢 lotype 和 Danny '365CSI' Engelman,我为我的项目找到了完美的解决方案。我用自定义事件和 EventBus 解决了它:
meal.js(型号)
get meals() {
const url = 'http://localhost:8080/meals';
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
}).then(res => {
return res.json()
}).then(data => {
let ce = new CustomEvent(this.ESSEN_CHANGE_EVENT, {
detail: {
action: this.ESSEN_LOAD_ACTION,
meals: data,
}
});
EventBus.dispatchEvent(ce);
});
},
EventBus.js(摘自书籍:Web Components in Action)
export default {
/**
* add event listener
* @param type
* @param cb
* @returns {{type: *, callback: *}}
*/
addEventListener(type, cb) {
if (!this._listeners) {
this._listeners = [];
}
let listener = {type: type, callback: cb};
this._listeners.push(listener);
return listener;
},
/**
* trigger event
* @param ce
*/
dispatchEvent(ce) {
this._listeners.forEach(function (l) {
if (ce.type === l.type) {
l.callback.apply(this, [ce]);
}
});
}
}
现在,当数据准备就绪时,将向事件总线发送一个信号。 meal-list-component
正在等待事件,然后获取数据:
export default class MealListComponent extends HTMLElement {
connectedCallback() {
this.attachShadow({mode: 'open'});
this.shadowRoot.innerHTML = Template.render();
this.dom = Template.mapDOM(this.shadowRoot);
// Load Speisekarte on init
this.dom.meals.innerHTML = Template.renderMeals(MealData.all);
// Custom Eventlistener - always triggers when essen gets added, deleted, updated etc.
EventBus.addEventListener(EssenData.ESSEN_CHANGE_EVENT, e => {
this.onMealChange(e);
});
}
onMealChange(e) {
switch (e.detail.action) {
case EssenData.ESSEN_LOAD_ACTION:
this.dom.meals.innerHTML = Template.renderMEals(e.detail.meals);
break;
}
}
}