Javascript异步编程

本文深入浅出地介绍了异步编程的概念及其在JavaScript中的应用。详细解释了异步、回调函数、事件监听、发布/订阅及Promises对象等核心概念,并通过实例展示了如何使用这些技术解决实际问题。

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


1、什么是异步(Asynchronous)编程?

    相对于同步(Synchronous)而言,异步就是后一个任务不需要等待前一个任务结束就执行,而前一个任务结束以后执行回调函数。

    最常见的异步编程有setTimeout函数、 ajax请求等。

    如:

        for (var i = 1; i <= 3; i++) {
            setTimeout(function(){
                console.log("#",i);
            }, 0);
            console.log("*",i);
        };

    输出的结果是:*1 *2 *3 #4 #4 #4

    涉及到的知识点: 异步、闭包、作用域

    setTimeout是一个注册事件,在主程序运行结束前,是不会调用的。

    就像为某个div绑定一个点击事件一样,在没点击之前,这个事件是不会被触发的。

    这就是一个常见的异步编程的例子。


2、异步编程的方法

    Ⅰ、回调函数

        假设有 f1(); f2(); 两个函数,其中f2()在等待f1()的执行结果。

        function f1(f2){
            setTimeout(function(){
              f2();
            }, 1000);
          }

        代码执行顺序:f1(f2);

        优点:f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行
        缺点:不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),而且每个任务只能指定一个回调函数
            
    Ⅱ、事件监听

        f1.on('done', f2);//jQuery写法,当f1发生done事件,就执行f2

        function f1(){
        setTimeout(function () {
          f1.trigger('done');//执行完成后,立即触发done事件
        }, 1000);
      }

        优点:可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化
        缺点:整个程序都要变成事件驱动型,运行流程会变得很不清晰


    Ⅲ、发布/订阅

        jQuery.subscribe("done", f2);//f2向jQuery订阅"done"信号

        function f1(){
       setTimeout(function () {
         jQuery.publish("done");//f1执行完成后,向jQuery发布"done"信号,从而引发f2的执行
       }, 1000);
     }


    Ⅳ、Promises对象   

        它的思想是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。比如,f1的回调函数f2,可以写成:

        f1().then(f2);

        对f1进行如下改写:

        function f1(){
       var dfd = $.Deferred();
       setTimeout(function () {
         dfd.resolve();
       }, 500);
       return dfd.promise;
     }

        优点:回调函数变成了链式写法,程序的流程可以看得很清楚,可以指定多个回调函数,如:

             f1().then(f2).then(f3);
             f1().then(f2).fail(f3);

        缺点:编写和理解,都相对比较难    

附几个概念:

一、事件

    事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。

二、注册事件
    
    注册事件分为属性注册和方法注册。

    属性注册:1.内嵌在DOM结构里的属性赋值

                HTML: <button onclick="sayHello()">点击</button>

                  JS: function sayHello() {
                             console.log('hello')
                      }

            2.通过JS来指定元素对象的属性赋值

                document.body.onclick = function (e) {
                    alert("为body注册一个点击事件");
                };

    方法注册:1.通过addEventListener()方法注册

                说明:在JS中,window、document、HtmlElement等对象可以通过addEventListener()方法注册事件的处理程序。

                语法:EventTarget.addEventListener(eventName, eventHandler, |useCapture )

                参数:

                    ①eventName {string} :所要注册的事件名称,不区分大小写。此名称不需要像注册事件属性那样前缀加上"on"。如注册鼠标点击事件,写为click。

                    ②eventHandler {function | function Object} :函数或者函数对象。事件触发时所需要执行的函数;当使用函数对象多次注册同一事件时,只当注册一遍。

                    ③useCapture {boolean} 可选 :是否处于捕获阶段,默认为false。

            多次注册:addEventListener()方法能为同一个对象的同一事件注册多次。当发生此事件时,注册的处理事件程序将按照注册先后顺序执行。

               注意:

                    ①IE9之前的IE的不支持此方法,可使用attachEvent()代替。

                    ②若使用相同的事件处理程序对象多次注册在同一个事件上,只算注册一次。

              例:

                      document.body.addEventListener('click',function(e){
                         console.log('被点击一');
                    });
                             
                    document.body.addEventListener('click',function(e){
                        console.log('被点击二');
                    });
                    
                    document.body.click(); // 输出: 被点击一 被点击二

            2.通过attachEvent()方法注册

              说明:IE9之前的IE版本可通过此方法注册事件。

              语法:EventTarget.attachEvent(eventName, eventHandler)
              
                      ①eventName {string} :所要注册的事件名称,区分大小写。这里的名称跟事件属性一样,以"on"开头,后面跟着事件名称。如:onclick、onload。
                      
                      ②eventHandler {function | function Object} :函数或者函数对象。事件触发时所需要执行的函数;当使用函数对象多次注册同一事件时,可注册多次(addEventListener()方法只当注册一次)。
              
          多次注册:attachEvent()方法能为同一个对象的同一事件注册多次。当触发此事件时,也会依次执行。

             例:

                  function sayHellow(){
                   console.log('hello');
                }
                document.body.attachEvent('onclick',sayHellow);
                document.body.attachEvent('onclick',sayHellow); // sayHellow第二次注册同一事件
                document.body.click(); //输出2次sayHellow函数 :hello hello

二、注销事件

        JS中,可调用removeEventListener()[注销addEventListener()] 和 detachEvent()[注销attachEvent()] 来注销元素的某个事件指定的处理程序,也可以给事件属性赋值null来注销此事件的所有绑定。
    
        1.removeEventListener(eventName, function Object)
        
        说明:注销通过addEventListener()注册的事件处理程序。
    
        语法:EventTarget.removeEventListener(eventName, eventHandlerObj)
        
        参数:
        
            ①eventName {string} :所要注销的事件名称,不区分大小写。此名称不需要像注册事件属性那样前缀加上"on"。如注册鼠标点击事件,写为click。
            
            ②eventHandlerObj {function Object} :函数对象。传入一个函数体是没有效果的。
    
        例:
            
            // 注销body click事件的sayHello函数
            document.body.removeEventListener('click',sayHello);

        2.detachEvent(eventName, function Object)

            说明:注销通过attachEvent()注册的事件处理程序。

            语法:EventTarget.detachEvent(eventName, eventHandlerObj)
            
            参数:
            
                ①eventName {string} :所要注销的事件名称,区分大小写。这里的名称跟事件属性一样,以"on"开头,后面跟着事件名称。如:onclick、onload。
                
                ②eventHandlerObj {function Object} ::函数对象。传入一个函数体是没有效果的。


           例:

                   // 注销body click事件的sayHello函数
                   document.body.detachEvent('onclick', sayHello);

        3.取消事件

            给对象的事件属性赋值为null,可取消此事件的所有注册过的处理事件程序。

            例:

                // onclick属性赋值为null,相当于注销了onclick事件
                document.body.onclick=null;


参考链接:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
                http://www.qdfuns.com/notes/17398/e8a1ce8f863e8b5abb530069b388a158/page/.html


    

资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 华为移动服务(Huawei Mobile Services,简称 HMS)是一个全面开放的移动服务生态系统,为企业和开发者提供了丰富的工具和 API,助力他们构建、运营和推广应用。其中,HMS Scankit 是华为推出的一款扫描服务 SDK,支持快速集成到安卓应用中,能够提供高效且稳定的二维码和条形码扫描功能,适用于商品扫码、支付验证、信息获取等多种场景。 集成 HMS Scankit SDK 主要包括以下步骤:首先,在项目的 build.gradle 文件中添加 HMS Core 库和 Scankit 依赖;其次,在 AndroidManifest.xml 文件中添加相机访问和互联网访问权限;然后,在应用程序的 onCreate 方法中调用 HmsClient 进行初始化;接着,可以选择自定义扫描界面或使用 Scankit 提供的默认扫描界面;最后,实现 ScanCallback 接口以处理扫描成功和失败的回调。 HMS Scankit 内部集成了开源的 Zxing(Zebra Crossing)库,这是一个功能强大的条码和二维码处理库,提供了解码、生成、解析等多种功能,既可以单独使用,也可以与其他扫描框架结合使用。在 HMS Scankit 中,Zxing 经过优化,以更好地适应华为设备,从而提升扫描性能。 通常,ScanKitDemoGuide 包含了集成 HMS Scankit 的示例代码,涵盖扫描界面的布局、扫描操作的启动和停止以及扫描结果的处理等内容。开发者可以参考这些代码,快速掌握在自己的应用中实现扫码功能的方法。例如,启动扫描的方法如下: 处理扫描结果的回调如下: HMS Scankit 支持所有安卓手机,但在华为设备上能够提供最佳性能和体验,因为它针对华为硬件进行了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值