GVKun编程网logo

链接两个异步jQuery函数时,如何完全避开jQuery Promise?(jquery怎么解决异步转同步)

28

在这篇文章中,我们将带领您了解链接两个异步jQuery函数时,如何完全避开jQueryPromise?的全貌,包括jquery怎么解决异步转同步的相关情况。同时,我们还将为您介绍有关AMD异步模块定义

在这篇文章中,我们将带领您了解链接两个异步jQuery函数时,如何完全避开jQuery Promise?的全貌,包括jquery怎么解决异步转同步的相关情况。同时,我们还将为您介绍有关AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法_jquery、ES6~Promise原理及使用三 搞懂jquery中的Promise(摘取自:https://www.cnblogs.com/lvdabao/p/jquery-deferred.html)、google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)、google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)_jquery的知识,以帮助您更好地理解这个主题。

本文目录一览:

链接两个异步jQuery函数时,如何完全避开jQuery Promise?(jquery怎么解决异步转同步)

链接两个异步jQuery函数时,如何完全避开jQuery Promise?(jquery怎么解决异步转同步)

我已经看过许多有关新EMCA的教程,这些教程承诺提倡在jQuery库中避免“承诺”。他们通常说您可以通过执行以下操作来躲避他们:

Promise.resolve($.getJSON(url, params)); // voila!  the jQuery promise is "gone"!

但是,当我必须将两个异步jQuery函数链接在一起时,这实际上不起作用。我如何将两个getJSON调用(第二个调用取决于第一个调用)链接在一起而不使用jQuery的then()或.when()?

相反,我只想使用Promise.all等。

我认为类似的问题是交错jquery和EMCA Promise?

答案1

小编典典

您可以采用两种方法之一…

转换然后合并:

var p1 = Promise.resolve($.getJSON(url_1, params_1)); // voila 1!var p2 = Promise.resolve($.getJSON(url_2, params_2)); // voila 2!var p3 = Promise.all([p1, p2]).then(...);

合并然后转换:

var p1 = $.getJSON(url_1, params_1);var p2 = $.getJSON(url_2, params_2);var p3 = Promise.resolve($.when(p1, p2)).then(...); // voila 1 and 2!

直截了当,两种方法都将为您提供本机的ES6 Promise,p3当两个jQuery Promise
都解决时,它就会解决;当其中一个Promise失败时,它就会被拒绝。

但是,您可能对这两个getJSON()调用的结果感兴趣,并且jQuery在这方面很尴尬。jQuery的jqXHR Promise将 多个
参数传递给它们的成功和错误回调,而ES6
Promise只接受一个。其余的将被忽略。幸运的是,将多个参数捆绑在一起以创建单个对象非常简单。必须先在jQuery中完成,然后再转换为ES6。

“转换然后合并”代码扩展如下:

var p1 = Promise.resolve($.getJSON(url_1, params_1).then(    function(data, textStatus, jqXHR) {        return { data:data, textStatus:textStatus, jqXHR:jqXHR };    },    function(jqXHR, textStatus, errorThrown) {        return { jqXHR:jqXHR, textStatus:textStatus, errorThrown:errorThrown };    }));var p2 = Promise.resolve($.getJSON(url_2, params_2).then(    function(data, textStatus, jqXHR) {        return { data:data, textStatus:textStatus, jqXHR:jqXHR };    },    function(jqXHR, textStatus, errorThrown) {        return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR };    }));var p3 = Promise.all([p1, p2]).then(    function(results) {        // results[0] will be an object with properties .data, .textStatus, .jqXHR         // results[1] will be an object with properties .data, .textStatus, .jqXHR     },    function(rejectVal) {        // rejectVal will be an object with properties .errorThrown, .textStatus, .jqXHR    });

“合并然后转换”方法比较棘手,因为合并的结果(在jQuery中)显示为arguments列表,列表本身需要转换(仍在jQuery中)为数组。

var p1 = $.getJSON(url_1, params_1).then(    function(data, textStatus, jqXHR) {         return { data:data, textStatus:textStatus, jqXHR:jqXHR };     },    function(jqXHR, textStatus, errorThrown) {         return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR };     });var p2 = $.getJSON(url_2, params_2).then(    function(data, textStatus, jqXHR) {         return { data:data, textStatus:textStatus, jqXHR:jqXHR };    },    function(jqXHR, textStatus, errorThrown) {         return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR };     });var p3 = Promise.resolve($.when(p1, p2).then(function() {    return [].slice.call(arguments);// <<< convert arguments list to Array})).then(    function(results) {         // results[0] will be an object with properties .data, .textStatus, .jqXHR        // results[1] will be an object with properties .data, .textStatus, .jqXHR    },    function(rejectVal) {         // rejectVal will be an object with properties .errorThrown, .textStatus, .jqXHR    });

AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法_jquery

AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法_jquery

AMD 模块

AMD(异步模块定义,Asynchronous Module Definition)格式总体的目标是为现在的开发者提供一个可用的模块化 JavaScript 的解决方案。

AMD 模块格式本身是一个关于如何定义模块的提案,在这种定义下模块和依赖项都能够异步地进行加载。它有很多独特的优势,包括天生的异步及高度灵活等特性,这些特性能够解除常见的代码与模块标识间的那种紧密耦合。目前它已经被很多项目所接纳,包括jQuery(1.7)。

RequireJS

RequireJS是一个工具库,主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范。

jQuery 对AMD的支持

jQuery 1.7 开始支持将 jQuery 注册为一个AMD异步模块。有很多兼容的脚本加载器(包括 RequireJS 和 curl)都可以用一个异步模块格式来加载模块,这也就表示不需要太多 hack 就能让一切运行起来。可以看看jQuery 1.7 中的源码:

复制代码 代码如下:

// Expose jQuery as an AMD module, but only for AMD loaders that
// understand the issues with loading multiple versions of jQuery
// in a page that all might call define(). The loader will indicate
// they have special allowances for multiple jQuery versions by
// specifying define.amd.jQuery = true. Register as a named module,
// since jQuery can be concatenated with other files that may use define,
// but not use a proper concatenation script that understands anonymous
// AMD modules. A named AMD is safest and most robust way to register.
// Lowercase jquery is used because AMD module names are derived from
// file names, and jQuery is normally delivered in a lowercase file name.
if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
 define( "jquery", [], function () { return jQuery; } );
}

其工作的原理是,所使用的脚本加载器通过指定一个属性,即 define.amd.jQuery 为 true,来标明自己可以支持多个 jQuery 版本。如果有兴趣了解特定的实现细节的话,我们可以将 jQuery 注册为一个具名模块,因为可能会有这样的风险,即它可能被与其它使用了 AMD 的 define() 方法的文件拼合在一起,而没有使用一个合适的、理解匿名 AMD 模块定义的拼合脚本。

高版本的jQuery (1.11.1) 去掉了define.amd.jQuery判断:

复制代码 代码如下:

if ( typeof define === "function" && define.amd ) {
 define( "jquery", [], function() {
  return jQuery;
 });
}

Require.js中使用jQuery

Require.js中使用jQuery非常方便,简单配置就可以了,例如:

复制代码 代码如下:

// 简单的配置
require.config({

    // RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。
    baseUrl: "./js",

    // 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了;
    paths: {

        "jquery": "libs/jquery-1.11.1.min.js"

    }

});

// 开始使用jQuery 模块
require(["jquery"], function ($) {

    //你的代码
    //这里直接可以使用jquery的方法,比如:$( "#result" ).html( "Hello World!" );

});

Require.js中使用jQuery 插件

虽然jQuery的支持AMD的API, 这并不意味着jQuery插件也是和AMD兼容的。

一般的jQuery 插件格式:

复制代码 代码如下:
(function ($) {
    $.fn.m​​yPlugin = function () {
        //你自己的插件代码
    };
})(jQuery);

不过我们稍微修改一下就可以使用Require.js加载一个jQuery插件:
复制代码 代码如下:

;(function (factory) {
    if (typeof define === "function" && define.amd) {
        // AMD模式
        define([ "jquery" ], factory);
    } else {
        // 全局模式
        factory(jQuery);
    }
}(function ($) {
    $.fn.jqueryPlugin = function () {
        //插件代码
    };
}));

Require.js中使用jQuery UI组件

Require.js中使用jQuery UI组件也类似的,只要改造一下jQuery Widget Factory 代码就可以了,并且感觉jQuery UI的依赖关系加载就可以了。例如:

复制代码 代码如下:

(function (widgetFactory) {

    if (typeof define === "function" && define.amd) {
        // AMD模式
        define("jquery.ui.widget", ["jquery"], function () {

            widgetFactory(window.jQuery);

        });
    } else {
        // 全局模式
        widgetFactory(window.jQuery);
    }
}
(function ($, undefined) {

    // jQuery Widget Factory 代码

}));

ES6~Promise原理及使用三 搞懂jquery中的Promise(摘取自:https://www.cnblogs.com/lvdabao/p/jquery-deferred.html)

ES6~Promise原理及使用三 搞懂jquery中的Promise(摘取自:https://www.cnblogs.com/lvdabao/p/jquery-deferred.html)

前两篇我们讲了ES6中的Promise以及Promise/A+规范,在Promise的知识体系中,jquery当然是必不可少的一环,所以本篇就来讲讲jquery中的Promise,也就是我们所知道的Deferred对象。   事实上,在此之前网上有很多文章在讲jquery Deferred对象了,但是总喜欢把ajax和Deferred混在一起讲,容易把人搞混。when、done、promise、success、error、fail、then、resolve、reject、always这么多方法不能揉在一起讲,需要把他们捋一捋,哪些是Deferred对象的方法,哪些是ajax的语法糖,我们需要心知肚明。  

先讲$.Deferred

jquery用$.Deferred实现了Promise规范,$.Deferred是个什么玩意呢?还是老方法,打印出来看看,先有个直观印象:
var def = $.Deferred();
console.log(def);
输出如下:

$.Deferred()返回一个对象,我们可以称之为Deferred对象,上面挂着一些熟悉的方法如:done、fail、then等。jquery就是用这个Deferred对象来注册异步操作的回调函数,修改并传递异步操作的状态。   Deferred对象的基本用法如下,为了不与ajax混淆,我们依旧举setTimeout的例子:

复制代码

function runAsync(){
    var def = $.Deferred();
    //做一些异步操作
    setTimeout(function(){
        console.log('执行完成');
        def.resolve('随便什么数据');
    }, 2000);
    return def;
}
runAsync().then(function(data){
    console.log(data)
});

复制代码

在runAsync函数中,我们首先定义了一个def对象,然后进行一个延时操作,在2秒后调用def.resolve(),最后把def作为函数的返回。调用runAsync的时候将返回def对象,然后我们就可以.then来执行回调函数。   是不是感觉和ES6的Promise很像呢?我们来回忆一下第一篇中ES6的例子:

复制代码

function runAsync(){
    var p = new Promise(function(resolve, reject){
        //做一些异步操作
        setTimeout(function(){
            console.log('执行完成');
            resolve('随便什么数据');
        }, 2000);
    });
    return p;           
}
runAsync()

复制代码

区别在何处一看便知。由于jquery的def对象本身就有resolve方法,所以我们在创建def对象的时候并未像ES6这样传入了一个函数参数,是空的。在后面可以直接def.resolve()这样调用。   这样也有一个弊端,因为执行runAsync()可以拿到def对象,而def对象上又有resolve方法,那么岂不是可以在外部就修改def的状态了?比如我把上面的代码修改如下:

复制代码

var d = runAsync();
d.then(function(data){
    console.log(data)
});
d.resolve('在外部结束');

复制代码

现象会如何呢?并不会在2秒后输出“执行完成”,而是直接输出“在外部结束”。因为我们在异步操作执行完成之前,没等他自己resolve,就在外部给resolve了。这显然是有风险的,比如你定义的一个异步操作并指定好回调函数,有可能被别人给提前结束掉,你的回调函数也就不能执行了。   怎么办?jquery提供了一个promise方法,就在def对象上,他可以返回一个受限的Deferred对象,所谓受限就是没有resolve、reject等方法,无法从外部来改变他的状态,用法如下:

复制代码

function runAsync(){
    var def = $.Deferred();
    //做一些异步操作
    setTimeout(function(){
        console.log('执行完成');
        def.resolve('随便什么数据');
    }, 2000);
    return def.promise(); //就在这里调用
}

复制代码

这样返回的对象上就没有resolve方法了,也就无法从外部改变他的状态了。这个promise名字起的有点奇葩,容易让我们搞混,其实他就是一个返回受限Deferred对象的方法,与Promise规范没有任何关系,仅仅是名字叫做promise罢了。虽然名字奇葩,但是推荐使用。  

then的链式调用

既然Deferred也是Promise规范的实现者,那么其他特性也必须是支持的。链式调用的用法如下:

复制代码

var d = runAsync();

d.then(function(data){
    console.log(data);
    return runAsync2();
})
.then(function(data){
    console.log(data);
    return runAsync3();
})
.then(function(data){
    console.log(data);
});

复制代码

与我们第一篇中的例子基本一样,可以参照。  

done与fail

我们知道,Promise规范中,then方法接受两个参数,分别是执行完成和执行失败的回调,而jquery中进行了增强,还可以接受第三个参数,就是在pending状态时的回调,如下:
deferred.then( doneFilter [, failFilter ] [, progressFilter ] )
除此之外,jquery还增加了两个语法糖方法,done和fail,分别用来指定执行完成和执行失败的回调,也就是说这段代码:

复制代码

d.then(function(){
    console.log('执行完成');
}, function(){
    console.log('执行失败');
});

复制代码

与这段代码是等价的:

复制代码

d.done(function(){
    console.log('执行完成');
})
.fail(function(){
    console.log('执行失败');
});

复制代码

 

always的用法

jquery的Deferred对象上还有一个always方法,不论执行完成还是执行失败,always都会执行,有点类似ajax中的complete。不赘述了。  

$.when的用法

jquery中,还有一个$.when方法来实现Promise,与ES6中的all方法功能一样,并行执行异步操作,在所有的异步操作执行完后才执行回调函数。不过$.when并没有定义在$.Deferred中,看名字就知道,$.when,它是一个单独的方法。与ES6的all的参数稍有区别,它接受的并不是数组,而是多个Deferred对象,如下:

复制代码

$.when(runAsync(), runAsync2(), runAsync3())
.then(function(data1, data2, data3){
    console.log('全部执行完成');
    console.log(data1, data2, data3);
});

复制代码

jquery中没有像ES6中的race方法吗?就是以跑的快的为准的那个方法。对的,jquery中没有。   以上就是jquery中Deferred对象的常用方法了,还有一些其他的方法用的也不多,干脆就不记它了。接下来该说说ajax了。  

ajax与Deferred的关系

jquery的ajax返回一个受限的Deferred对象,还记得受限的Deferred对象吧,也就是没有resolve方法和reject方法,不能从外部改变状态。想想也是,你发一个ajax请求,别人从其他地方给你取消掉了,也是受不了的。   既然是Deferred对象,那么我们上面讲到的所有特性,ajax也都是可以用的。比如链式调用,连续发送多个请求:

复制代码

req1 = function(){
    return $.ajax(/*...*/);
}
req2 = function(){
    return $.ajax(/*...*/);
}
req3 = function(){
    return $.ajax(/*...*/);
}

req1().then(req2).then(req3).done(function(){
    console.log('请求发送完毕');
});

复制代码

明白了ajax返回对象的实质,那我们用起来就得心应手了。  

success、error与complete

这三个方法或许是我们用的最多的,使用起来是这样的:
$.ajax(/*...*/)
.success(function(){/*...*/})
.error(function(){/*...*/})
.complete(function(){/*...*/})
分别表示ajax请求成功、失败、结束的回调。这三个方法与Deferred又是什么关系呢?其实就是语法糖,success对应done,error对应fail,complete对应always,就这样,只是为了与ajax的参数名字上保持一致而已,更方便大家记忆,看一眼源码:
deferred.promise( jqXHR ).complete = completeDeferred.add;
jqXHR.success = jqXHR.done;
jqXHR.error = jqXHR.fail;
complete那一行那么写,是为了减少重复代码,其实就是把done和fail又调用一次,与always中的代码一样。deferred.promise( jqXHR )这句也能看出,ajax返回的是受限的Deferred对象。   jquery加了这么些个语法糖,虽然上手门槛更低了,但是却造成了一定程度的混淆。一些人虽然这么写了很久,却一直不知道其中的原理,在面试的时候只能答出一些皮毛,这是很不好的。这也是我写这篇文章的缘由。   jquery中Deferred对象涉及到的方法很多,本文尽量分门别类的来介绍,希望能帮大家理清思路。总结一下就是:$.Deferred实现了Promise规范,then、done、fail、always是Deferred对象的方法。$.when是一个全局的方法,用来并行运行多个异步任务,与ES6的all是一个功能。ajax返回一个Deferred对象,success、error、complete是ajax提供的语法糖,功能与Deferred对象的done、fail、always一致。就酱。

google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)

google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)

1. 很多网站都是使用这种方式引入,客户的浏览器可能已经缓存过了 jquery。可以直接调用本地的,速度更快…
2. Google code 使用了 cdn 技术在很多地方有节点服务器,加载 jquery 时绝对不会比在你服务器上加载慢,本地服务器除外 : )
3. 可以节省服务器流量,降低服务器带宽压力

可以使用两种方式引用 google code 的jquery
一、引用 http://www.google.com/jsapi?key=Goolge 密钥
<script type="text/javascript">
google.load("jquery","1.4.2");
</script>

二、直接引用地址http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js


jQuery 1.2.6 引用文件
复制代码 代码如下:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>

google jQuery 1.3.2引用文件
复制代码 代码如下:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script>

google jQuery 1.4.2引用文件
复制代码 代码如下:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>

google jQuery 1.5.2引用文件
复制代码 代码如下:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js" type="text/javascript"></script>

google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)_jquery

google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)_jquery

1. 很多网站都是使用这种方式引入,客户的浏览器可能已经缓存过了 jquery。可以直接调用本地的,速度更快…
2. Google code 使用了 cdn 技术在很多地方有节点服务器,加载 jquery 时绝对不会比在你服务器上加载慢,本地服务器除外 : )
3. 可以节省服务器流量,降低服务器带宽压力

可以使用两种方式引用 google code 的jquery
一、引用 http://www.google.com/jsapi?key=Goolge 密钥


二、直接引用地址http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js


jQuery 1.2.6 引用文件

复制代码 代码如下:



google jQuery 1.3.2引用文件
复制代码 代码如下:



google jQuery 1.4.2引用文件
复制代码 代码如下:



google jQuery 1.5.2引用文件
复制代码 代码如下:


关于链接两个异步jQuery函数时,如何完全避开jQuery Promise?jquery怎么解决异步转同步的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法_jquery、ES6~Promise原理及使用三 搞懂jquery中的Promise(摘取自:https://www.cnblogs.com/lvdabao/p/jquery-deferred.html)、google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)、google jQuery 引用文件,jQuery 引用地址集合(jquery 1.2.6至jquery1.5.2)_jquery的相关知识,请在本站寻找。

本文标签: