前端异步(async)解决方案(所有方案)

1,100 阅读7分钟

JavaScript是一门单线程语言,即一次只能完成一个任务,若有多个任务要执行 ,则必须排队按照队列来执行(前一个任务完成,再执行下一个任务)

这种模式执行简单,但随着日后的需求,事务,请求增多,这种单线程模式执行效率必定低下。只要有一个任务执行消耗了很长时间,在这个事件后面的任务无法执行。常见的浏览器无响应(假死),往往就是因为某一段JavaScript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。(弊端)

为了解决这个问题,JavaScript语言将任务执行模式分成同步和异步:

同步模式:就是上面所说的一种执行模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的,同步的。

**异步模式:**就是每一个任务有一个有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,二是执行回调函数,后一个任务则是不等前一个任务结束就执行,所有程序的执行顺序与任务排序是不一致的,异步的。

“异步模式”非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,“异步模式”甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧就是急剧下降,很快就会失去响应。(异步莫斯的重要性)

下面就带来几种前端异步解决方案:

(一)传统方案

1.回调函数(callback)

异步编程的基本方法:

首先需要声明,回调函数只是一种实现,并不是异步模式特有的实现。

回调函数的定义:

函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。

生活举例:约会结束后你送你女朋友回家,离别时,你肯定会说:“到家了给我发条信息,我很担心你。” 然后你女朋友回家以后还真给你发了条信息。其实这就是一个回调的过程。你留了个参数函数(要求女朋友给你发条信息)给你女朋友,然后你女朋友回家,回家的动作是主函数。她必须先回到家以后,主函数执行完了,再执行传进去的函数,然后你就收到一条信息了。

案例:

//定义主函数,回调函数作为参数
function A(callback) {
    callback();  
    console.log('我是主函数');      
}
 
//定义回调函数
function B(){
    setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作  
}
 
//调用主函数,将函数B传进去
A(B);
 
//输出结果
我是主函数
我是回调函数

上面的代码中,我们先定义了主函数和回调函数,然后再去调用主函数,将回调函数传进去。

定义主函数的时候,我们让代码先去执行callback()回调函数,但输出结果却是后输出回调函数的内容。这就说明了主函数不用等待回调函数执行完,可以接着执行自己的代码。所以一般回调函数都用在耗时操作上面。比如ajax请求,比如处理文件等。

**优点:**简单,容易理解和 部署。

**缺点:**不利于代码的阅读,和维护,各部分之间高度耦合,流程会很混乱,而且每一个任务只能指定一个回调函数。

(二)工具方案

工具方案大致分为以下5个:

*  Promise
*  gengerator
*  async await
*  node.js中nextTick setImmiddate
*  第三方库async.js

下面针对每一个做详细说明应用:

1.Promise(重点)

(1)Promise的含义和发展:

**含义:**Promise对象用于一个异步操作的最终完成(或失败)及其结果值的表示。简单点说,它就是用于处理异步操作的,异步处理成功了就执行成功的操作,异步处理失败了就捕获错误或者停止后续操作。

**发展:**Promise是异步编程的一种解决方案,比传统的解决方案-回调函数和事件---更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了语法,原生提供了Promise

(2)它的一般形式

new Promise(
    /* executor**/
    function(resolve,reject){
        if(/*success*/){
            //执行代码
            resolve();
        }else{/*fail*/
            //执行代码
            reject();
        }
    }

(二)常见的浏览器存储方式(cookie、localStorage、sessionStorage)

我们常用的存储方式主要由两种:cookie、webStorage(localStorage个sessionStorage)

1.cookie

Cookie基于HTTP规范,用来识别用户。

Cookie是服务器发送到浏览器的一小段数据,会在浏览器下次向同一服务器发起请求时被携带并发送到服务器上。

Cookie诞生之初的作用就是解决HTTP的无状态请求,用来记录一些用户相关的一些状态。

*会话状态管理(如用户登录状态、购物车、游戏分数或其他需要记录的信息)

*个性化设置(如用户自定义设置、主题等)

*浏览器行为跟踪(如跟踪分析用户行为等)

因为一些前端交互的需要,后来cookie也被用于存储一些客户端的数据。

Cookie的原生api不友好,需要自行封装一下。下面是封装后的方法。

创建cookie

1234567891011
/*** 
@description js原生设置cookie* 
@param {String} name 给你要设置的cookie起个名字(key)* 
@param {String} value cookie的具体内容(value)* 
@param {String} expiredays 设置cookie的过期时间,单位:天*/
function setCookie(name, value, expiredays) {
    var exdate=new Date();
    exdate.setDate(exdate.getDate() + expiredays);
    document.cookie = name + '=' + escape(value)+ ((expiredays == null) ? '' : ';
    expires=' +exdate.toGMTString());
}

获取cookie

/*** 
@description js原生获取cookie方法1* 
@param {String} name 你要获取的cookie名*/
function getCookie(name) {  
    if (document.cookie.length > 0) {    
        var start = document.cookie.indexOf(name + '=');    
        if (start !== -1) {      
            start = start + name.length + 1;      
            var end = document.cookie.indexOf(';', start);      
        if (end === -1) {        
            end = document.cookie.length;        
            return unescape(document.cookie.substring(start, end));      
}   
} 
 }  
return '';} 

/*** 
@description js原生获取cookie方法2* 
@param {String} name 你要获取的cookie名*/
function getCookie(name) {  
    var cookieArr = document.cookie.split(';') || [];  
    if(!cookieArr.length){    
        return '';  
    }  
    for(var i = 0; i < cookieArr.length; i ++){    
        var key = $.trim(cookieArr[i]).split('=')[0];    
        var value = $.trim(cookieArr[i]).split('=')[1];    
        if(key === name){      
            return value;    
        }  
     }}

检查cookie是否已存在

function checkCookie() {  
    username = getCookie('username');  
    if (username !== null && username !== '') {    
        alert('Welcome again ' + username + '!');  
    } else {    
    username = prompt('Please enter your name:', '');    
    if (username !== null && username !== '') {      
        setCookie('username',username,365);    
    }  
}}

jquery.cookie.js封装的cookie设置方法:

创建cookie

/*** 
'name', cookie命名* 'value',cookie的值* {*   expires: 7, // cookie有效期,单位天;默认值:会话cookie,关闭浏览器cookie失效。*   path: '/', // cookie影响到的路径;值为'/',表示设置cookie在整个域中可用;默认值:创建cookie的页面路径。*   domain: 'example.com', // 定义cookie有效的域。默认值:创建cookie的页面域。*   secure: false, // 定义cookie安全性,默认值:false,设置为true,则cookie在http中是无效的,cookie的传输需要使用安全协议(https)。* }*/$.cookie('name', 'value', { expires: 7, path: '/', domain: 'example.com', secure: false});

读取cookie

$.cookie('name'); //name存在返回对应value,不存在返回null

读取所有可用的cookies:

$.cookie(); //{'name': value}

TODO:直接调用会报错?

删除cookie

1

2

3

//成功删除cookie时返回true,否则返回false

$.removeCookie(``'name'``); // => true

$.removeCookie(``'nothing'``); // => false

注意:删除cookie时,必须传递用于设置cookie的完全相同的路径,域和安全选项,除非您依赖于默认选项。

即:设置cookie时如果设置了path属性或secure属性,删除的时候要带着这些属性,否则无法成功删除cookie。

1

2

3

4

5

// This won't work!

$.removeCookie('name``'); // => false

// This will work!

$.removeCookie('``name``', { path: '``/' }); // => true

TODO:$.removeCookie无效?

(jquery1.9.1.js + jquery.cookie.js,插件无重复引用的情况,$.removeCookie提示undefined)

2.webStorage基于HTML5规范

HTML5提供了两种在客户端存储数据的新方法:localStorage和sessionStorage,挂载在window对象下。

webStorage是本地存储,数据不是由服务器请求传递的。从而它可以存储大量的数据,而不影响网站的性能。

Web Storage的目的是为了克服由cookie带来的一些限制,当数据需要被雅阁控制在客户端上时,无须持续地将数据发挥服务器。比如客户端需要保存的一些用户行为或数据,或从接口获取的一些短期内不会更新的数据,我们就可以利用Web Storage来存储。

localStorage的声明周期是永久性的。localStorage存储的数据,即使关闭浏览器,也不会让数据小时,除非主动的去删除数据。如果想设置失效事件,需自行封装。

sessionStorage的生命周期是在浏览器关闭前。

特性:

*关闭浏览器sessionStorage失效;
*页面刷新不会消除数据;
*只有在当前页面打开链接,才可以访sessionStorage的数据,使用window.open打开页面和改变
location.href方式都可以获取到sessionStorage内部的数据;

存储方式

作用与特性

存储数量及大小

api

cookie

● 存储用户信息,获取数据需要与服务器建立连接。

● 可存储的数据有限,且依赖于服务器,无需请求服务器的数据尽量不要存放在cookie中,以免影响页面性能。

● 可设置过期时间。

● 最好将cookie控制在4095B以内,超出的数据会被忽略。

● IE6或更低版本最多存20个cookie; IE7及以上版本最多可以有50个;Firefox最多50个;chrome和Safari没有做硬性限制。

原生、$.cookie(详见上文)

localStorage

● 存储客户端信息,无需请求服务器。

● 数据永久保存,除非用户手动清理客户端缓存。

● 开发者可自行封装一个方法,设置失效时间。

5M左右,各浏览器的存储空间有差异。(感兴趣的同学可以自己试一下)。

// 保存数据到 localStorage

localStorage.setItem('key', 'value');

// 从 localStorage 获取数据

let data = localStorage.getItem('key');

// 从 localStorage 删除保存的数据

localStorage.removeItem('key');

// 从 localStorage 删除所有保存的数据

localStorage.clear();

sessionStorage

● 存储客户端信息,无需请求服务器。

● 数据保存在当前会话,刷新页面数据不会被清除,结束会话(关闭浏览器、关闭页面、跳转页面)数据失效。

同localStorage

// 保存数据到 sessionStorage

sessionStorage.setItem('key', 'value');

// 从 sessionStorage 获取数据

let data = sessionStorage.getItem('key');

// 从 sessionStorage 删除保存的数据

sessionStorage.removeItem('key');

// 从 sessionStorage 删除所有保存的数据

sessionStorage.clear();

localStorage二次封装----设置过期时间

export default{
            set(key,data,time){
                let obj={
                    data=data,
                    ctime:(new Date()).getTime(),//时间戳,同Date.now()
                    express:1000*60*60//设置过期时间一个小时
                }
                localStorage.setItem(key,JSON.stringify(obj));
            },
            get(key){
                let obj=JSON.parse(localStorage.getItem(key));
                let getItem=(new Date()).getTime();
                if(getItem-obj.ctime>=express){
                    localStorage.removeItem(key);
                    return null;
                }else{
                    return obj.data;
                }
            }
        }