异步请求接收节点插入优化:能否直接在元素创建时绑定服务器响应结果以避免变量依赖?
this.j() as child elements when creating a DOM node? Short answer: No, you can't use this.element = el('div', { className: "header" }, ...this.j({news: id_news})); directly—here's why, plus how to achieve your desired outcome.
Why the direct approach fails
Your this.j() method returns a Promise (since it wraps fetch, which is asynchronous). When you try to spread ...this.j(...) into the el() function, you're spreading a Promise object, not the actual array of data from your server. The browser will treat this Promise as a text node, resulting in something like [object Promise] being rendered instead of your desired content.
Asynchronous operations don't return their final value immediately—they return a Promise that resolves to the value later. So we need to handle that resolution explicitly.
How to achieve your goal (no this.element variable, auto-update after response)
Your goal is to create the header element, add it to the DOM right away, and have its children populate automatically once the server responds—without storing the element in a this.element variable. Here's how to do that cleanly:
Step 1: Refactor j() to return a data Promise
First, modify the j() method to return a Promise that resolves to your server's response data (instead of relying on a callback). This makes it easier to chain asynchronous operations:
j(ms) { return fetch(document.URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(ms) }) .then(async (response) => { const res = await response.json(); if (res.ms) { alert(res.ms); throw new Error(res.ms); // Throw error to handle failures later } return res; // Return the data so we can use it in the next step }); }
Step 2: Create the element, add it to DOM, then update it asynchronously
Now you can create the header element, insert it into the DOM immediately, and update its children once the Promise resolves—no need to store it in this.element:
int() { // Create the header element, add a loading state, and insert it into the DOM const headerEl = el('div', { className: "header" }, el('div', { textContent: 'Loading news...' }) ); // Insert into your target parent element (replace document.body with your actual parent) document.body.append(headerEl); // Fetch data and update the header once the response arrives this.j({news: id_news}) .then(response => { headerEl.replaceChildren( ...response.map(item => el('div', { textContent: item[1] })) ); }) .catch(() => { // Handle errors (e.g., show a failure message) headerEl.replaceChildren(el('div', { textContent: 'Failed to load news' })); }); }
Even cleaner: Skip the temporary variable (if you really want to)
If you want to avoid even the headerEl temporary variable, you can use a closure or chain DOM queries—but note that this can reduce readability slightly:
int() { // Create, insert, and update in one chain document.body.append( el('div', { className: "header" }, el('div', { textContent: 'Loading news...' })) ) // Grab the newly inserted header element .querySelector('.header') // Update it once data arrives && this.j({news: id_news}) .then(response => { document.querySelector('.header').replaceChildren( ...response.map(item => el('div', { textContent: item[1] })) ); }) .catch(() => { document.querySelector('.header').replaceChildren(el('div', { textContent: 'Failed to load news' })); }); }
Key takeaways
- Asynchronous functions like
fetchreturn Promises, not immediate values—you can't spread them as DOM children directly. - Refactoring
j()to return a data Promise makes it easy to chain updates to your DOM element. - Using a temporary variable like
headerElis perfectly acceptable (and improves readability) but if you want to avoid it, closures or DOM queries work too.
内容的提问来源于stack exchange,提问作者Дмитрий Варзанов

