Execution of JavaScript Programs

本文详细解析了JavaScript在浏览器中的执行过程,包括脚本加载、执行时机、事件处理等关键环节,并探讨了不同阶段脚本如何影响页面加载及用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

13.5. Execution of JavaScript Programs

The previous sections discussed the mechanics of integrating JavaScript code into an HTML file. Now the following sections discuss exactly how and when that integrated JavaScript code is executed by the JavaScript interpreter.

13.5.1. Executing Scripts

JavaScript statements that appear between <script> and </script> tags are executed in the order that they appear in the script. When a file has more than one script, the scripts are executed in the order in which they appear (with the exception of scripts with the defer attribute, which IE executes out of order). The JavaScript code in <script> tags is executed as part of the document loading and parsing process.

Any <script> element that does not have a defer attribute may call the document.write( ) method (described in detail in Chapter 15). The text passed to this method is inserted into the document at the location of the scripts. When the script is finished executing, the HTML parser resumes parsing the document, starting with any text output by the script.

Scripts can appear in the <head> or the <body> of an HTML document. Scripts in the <head> typically define functions to be called by other code. They may also declare and initialize variables that other code will use. It is common for scripts in the <head> of a document to define a single function and then register that function as an onload event handler for later execution. It is legal, but uncommon, to call document.write( ) in the <head> of a document.

Scripts in the <body> of a document can do everything that scripts in the <head> can do. It is more common to see calls to document.write( ) in these scripts, however. Scripts in the <body> of a document may also (using techniques described in Chapter 15) access and manipulate document elements and document content that appear before the script. As described later in this chapter, however, document elements are not guaranteed to be available and stable when the scripts in the <body> are executed. If a script simply defines functions and variables to be used later and does not call document.write( ) or otherwise attempt to modify document content, convention dictates that it should appear in the <head> of the document instead of the <body>.

As previously mentioned, IE executes scripts with the defer attribute out of order. These scripts are run after all nondeferred scripts and after the document is fully parsed, but before the onload event handler is triggered.

13.5.2. The onload Event Handler

After the document is parsed, all scripts have run, and all auxiliary content (such as images) has loaded, the browser fires the onload event and runs any JavaScript code that has been registered with the Window object as an onload event handler. An onload handler can be registered by setting the onload attribute of the <body> tag. It is also possible (using techniques shown in Chapter 17) for separate modules of JavaScript code to register their own onload event handlers. When more than one onload handler is registered, the browser invokes all handlers, but there is no guarantee about the order in which they are invoked.

When the onload handler is triggered, the document is fully loaded and parsed, and any document element can be manipulated by JavaScript code. For this reason, JavaScript modules that modify document content typically contain a function to perform the modification and event-registration code that arranges for the function to be invoked when the document is fully loaded.

Because onload event handlers are invoked after document parsing is complete, they must not call document.write( ). Instead of appending to the current document, any such call would instead begin a new document and overwrite the current document before the user even had a chance to view it.

13.5.3. Event Handlers and JavaScript URLs

When document loading and parsing ends, the onload handler is triggered, and JavaScript execution enters its event-driven phase. During this phase, event handlers are executed asynchronously in response to user input such as mouse motion, mouse clicks, and key presses. JavaScript URLs may be invoked asynchronously during this phase as well, if, for example, the user clicks on a link whose HRef attribute uses the javascript: pseudoprotocol.

<script> elements are typically used to define functions, and event handlers are typically used to invoke those functions in response to user input. Event handlers can define functions, of course, but this is an uncommon (and not very useful) thing to do.

If an event handler calls document.write( ) on the document of which it is a part, it will overwrite that document and begin a new one. This is almost never what is intended, and, as a rule of thumb, event handlers should never call this method. Nor should they call functions that call this method. The exception, however, is in multiwindow applications in which an event handler in one window invokes the write( ) method of the document of a different window. (See Section 14.8. for more on multiwindow JavaScript applications.)

13.5.4. The onunload Event Handler

When the user navigates away from a web page, the browser triggers the onunload event handler, giving the JavaScript code on that page one final chance to run. You can define an onunload handler by setting the onunload attribute of the <body> tag or with other event-handler registration techniques described in Chapter 17.

The onunload event enables you to undo the effects of your onload handler or other scripts in your web page. For example, if your application opens up a secondary browser window, the onunload handler provides an opportunity to close that window when the user leaves your main page. The onunload handler should not run any time-consuming operation, nor should it pop up a dialog box. It exists simply to perform a quick cleanup operation; running it should not slow down or impede the user's transition to a new page.

13.5.5. The Window Object as Execution Context

All scripts, event handlers, and JavaScript URLs in a document share the same Window object as their global object. JavaScript variables and functions are nothing more than properties of the global object. This means that a function declared in one <script> can be invoked by the code in any subsequent <script>.

Since the onload event is not triggered until after all scripts have executed, every onload event handler has access to all functions defined and variables declared by all scripts in the document.

Whenever a new document is loaded into a window, the Window object for that window is restored to its default state: any properties and functions defined by a script in the previous document are deleted, and any of the standard system properties that may have been altered or overwritten are restored. Every document begins with a clean slate. Your scripts can rely on this; they will not inherit a corrupted environment from the previous document. This also means that any variables and functions your scripts define persist only until the document is replaced with a new one.

The properties of a Window object have the same lifetime as the document that contains the JavaScript code that defined those properties. A Window object itself has a longer lifetime; it exists as long as the window it represents exists. A reference to a Window object remains valid regardless of how many web pages the window loads and unloads. This is relevant only for web applications that use multiple windows or frames. In this case, JavaScript code in one window or frame may maintain a reference to another window or frame. That reference remains valid even if the other window or frame loads a new document.

13.5.6. Client-Side JavaScript Threading Model

The core JavaScript language does not contain any threading mechanism, and client-side JavaScript does not add any. Client-side JavaScript is (or behaves as if it is) single-threaded. Document parsing stops while scripts are loaded and executed, and web browsers stop responding to user input while event handlers are being executed.

Single-threaded execution makes for much simpler scripting: you can write code with the assurance that two event handlers will never run at the same time. You can manipulate document content knowing that no other thread is attempting to modify it at the same time.

Single-threaded execution also places a burden on JavaScript programmers: it means that JavaScript scripts and event handlers must not run for too long. If a script performs a computationally intensive task, it will introduce a delay into document loading, and the user will not see the document content until the script completes. If an event handler performs a computationally intensive task, the browser may become nonresponsive, possibly causing the user to think that it has crashed.[*]

[*] Some browsers, such as Firefox, guard against denial-of-service attacks and accidental infinite loops, and prompt the user if a script or event handler takes too long to run. This gives the user the chance to abort a runaway script.

If your application must perform enough computation to cause a noticeable delay, you should allow the document to load fully before performing that computation, and you should be sure to notify the user that computation is underway and that the browser is not hung. If it is possible to break your computation down into discrete subtasks, you can use methods such as setTimeout( ) and setInterval( ) (see Chapter 14) to run the subtasks in the background while updating a progress indicator that displays feedback to the user.

13.5.7. Manipulating the Document During Loading

While a document is being loaded and parsed, JavaScript code in a <script> element can insert content into the document with document.write( ). Other kinds of document manipulation, using DOM scripting techniques shown in Chapter 15, may or may not be allowed in <script> tags.

Most browsers seem to allow scripts to manipulate any document elements that appear before the <script> tag. Some JavaScript coders do this routinely. However, no standard requires it to work, and there is a persistent, if vague, belief among some experienced JavaScript coders that placing document manipulation code within <script> tags can cause problems (perhaps only occasionally, only with some browsers, or only when a document is reloaded or revisited with the browser's Back button).

The only consensus that exists in this gray area is that it is safe to manipulate the document once the onload event has been triggered, and this is what most JavaScript applications do: they use the onload handler to trigger all document modifications. I present a utility routine for registering onload event handlers in Example 17-7.

In documents that contain large images or many images, the main document may be parsed well before the images are loaded and the onload event is triggered. In this case, you might want to begin manipulating the document before the onload event. One technique (whose safety is debated) is to place the manipulation code at the end of the document. An IE-specific technique is to put the document manipulation code in a <script> that has both defer and src attributes. A Firefox-specific technique is to make the document-manipulation code an event handler for the undocumented DOMContentLoaded event, which is fired when the document is parsed but before external objects, such as images, are fully loaded.

Another gray area in the JavaScript execution model is the question of whether event handlers can be invoked before the document is fully loaded. Our discussion of the JavaScript execution model has so far concluded that all event handlers are always triggered after all scripts have been executed. While this typically happens, it is not required by any standard. If a document is very long or is being loaded over a slow network connection, the browser might partially render the document and allow the user to begin interacting with it (and triggering event handlers) before all scripts and onload handlers have run. If such an event handler invokes a function that is not yet defined, it will fail. (This is one reason to define all functions in scripts in the <head> of a document.) And if such an event handler attempts to manipulate a part of the document that has not yet been parsed, it will fail. This scenario is uncommon in practice, and it is not usually worth the extra coding effort required to aggressively protect against it.

### Vue 3 渲染函数执行期间的未处理错误解决方案 在 Vue 3 中,`Unhandled error during execution of render function` 错误通常表明组件的模板或渲染逻辑存在问题。这种问题可能是由于数据绑定不正确、异步操作未完成或者响应式对象未被正确定义引起的。 以下是针对该问题的具体分析和解决方法: #### 数据初始化的重要性 Vue 3 的响应式系统基于 Proxy 对象实现,这意味着如果某个属性未提前声明,则可能会导致运行时错误。例如,在 `data()` 函数中返回的对象必须包含所有后续会使用的键值对[^1]。 如果没有预先定义这些键值对,当尝试访问它们时,可能导致未捕获的异常。 对于用户的场景,可以确认以下几点: - **确保初始状态已定义**:在 `data()` 或组合 API (`setup()`) 中显式地初始化变量是非常重要的。 - 如果使用的是选项 API (Options API),则需要像下面这样设置默认值: ```javascript export default { data() { return { goodsInfo: { info: {} }, // 初始化嵌套结构 }; }, }; ``` #### 解决方案一:调整 Options API 使用方式 通过修改原始代码来适配 Vue 3 更严格的响应式机制,如下所示: ```javascript // 原始写法可能存在风险 this.goodsInfo.info = res.data.data; // 改进建议 if (!this.goodsInfo || !this.goodsInfo.info) { this.goodsInfo = { info: {} }; // 防止 undefined 导致崩溃 } Object.assign(this.goodsInfo.info, res.data.data); ``` 此更改能够有效防止因 `goodsInfo` 或其子字段不存在而引发的潜在问题[^1]。 #### 解决方案二:采用 Composition API 替代传统 Data 方法 Composition API 是 Vue 3 推荐的新模式之一,它提供了更灵活的方式管理复杂的状态逻辑。利用 reactive 和 ref 可以更好地控制组件内的数据流并减少类似的错误发生几率。 下面是转换后的版本示例: ```javascript import { defineComponent, reactive } from 'vue'; export default defineComponent({ setup(props, context) { const state = reactive({ goodsInfo: { info: {} } }); async function fetchData() { try { const response = await someApiCall(); // 模拟网络请求 Object.assign(state.goodsInfo.info, response.data); } catch(error){ console.error('Failed to fetch data', error); } } fetchData(); return { ...state }; } }); ``` 在此例子中,我们采用了 `reactive` 来创建可变状态容器,并且保证了即使服务器端返回的数据为空也不会影响前端展示效果[^1]。 #### 调试技巧提示 为了进一步排查此类问题,建议启用开发工具中的错误跟踪功能以及审查具体的堆栈信息。此外还可以考虑增加全局错误处理器以便及时发现隐藏隐患: ```javascript app.config errorHandler = err => { alert(`Error occurred: ${err.message}`); }; ``` --- ### 总结 综上所述,“Unhandled error during execution of scheduler flush/render function” 往往源于未能妥善初始化某些依赖项或者是跨生命周期阶段不当调用了尚未准备好的资源所致。遵循以上指导原则应该可以帮助您规避大部分常见陷阱。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值