异步编程

异步编程

一:同步与异步

同步:Javascript是一种单线程语言。单线程也就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务。同步具体表现为:JS文件中的代码从上往下连续执行。

如果有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。

异步:就是代码执行的顺序并不是按照从上到下的顺序一次性一次执行,而是在不同的时间段执行,一部分代码在“未来执行”。排在异步任务后面的代码,不用等待异步任务结束会马上运行,也就是说,异步任务不具有”堵塞“效应。

二:异步编程方法

回调函数(Callback)

回调函数是异步操作最基本的方法。如下ajax网络请求执行成功后调用success()

$.ajax({url:"/url",success:function(result){
	//逻辑代码
}});

如果多个请求存在依赖性,你可能就会写出如下代码产生回调地狱,不利于代码的阅读和维护,各个部分之间高度耦合,使得程序结构混乱。

ajax('url1', function(){
    A();
    ajax('url2', function(){
        B();
        ajax('url3', function(){
        	C();
    	}
    }
});

promise

Promise 对象为异步而生,只是个异步操作容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的最终完成或失败状态, 及异步操作结果值。用链式调用解决了回调地狱。

Promise对象代表一个异步操作,有三种状态:

  • pending 进行中

  • fulfilled 已成功

  • rejected 已失败

    对象的状态不受外界影响。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

    Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。

用法:Promise构造函数

构造函数主要是用于包装还未支持promises的函数。

语法:var promise = new Promise( function(resolve, reject) {...} /* executor */ );

语法点1:executor函数

带有 resolvereject 两个参数。Promise构造函数执行时立即调用executor 函数, resolvereject 两个函数作为参数传递给executor

1.executor函数执行一些异步操作:

异步操作成功:调用resolve函数将 状态改成fulfilled

Promise.resolve(value):

返回一个状态由给定value决定的Promise对象:

​ 该value为空,基本类型或者不带then方法的对象返回的Promise对象状态为fulfilled,并且将该value传递给对 应的then方法;

​ 如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定。如果你 不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value 以Promise对象形式使用。

异步操作失败:调用reject 函数将promise的状态改为rejected。

如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

Promise.reject(reason):

​ 返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法

2.executor函数中执行一些同步操作:

执行顺序:executor函数中的同步代码会优于函数内的异步代码执行。当调用resolve/reject方法改变promise的状态后then方法才会被调用。

<script>
const promise = new Promise((resolve, reject) => {  
  console.log('同步打印1:promise start');  

  // 异步操作
  setTimeout(()=>{   
    for (let index = 0; index < 2; index++) {  
      console.log('Promise' + index);    
    }  

    resolve('promise done');  

  },1000);  
  
  console.log('同步打印2:promise end');  
});

console.log('同步打印3');  

promise.then((v)=>{console.log(v)}); 

/*上面代码的打印执行顺序
同步打印2:promise end
同步打印3
Promise0
Promise1
promise done
*/
</script>
语法点2:then()

then() 方法返回一个 Promise。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。

Promise.prototype.then(onFulfilled, onRejected)

​ pending 状态的 Promise 对象变为fulfilled 状态时传递一个值给相应的状态处理方法,或者变为rejected状态 并传递失败信息。

​ 1.当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用

​ 2.then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型,为then的回调函数。

​ 3.当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,该方法有一个参数,即接受的最终结果。,

​ 当Promise状态为rejected时,调用 then 的 onrejected 方法, 该函数有一个参数,即拒绝的原因。

​ 所以在异步操作的完成和绑定处理方法之间不存在竞争,异步完成在前,then方法执行在后

​ 4.then方法返回值:返回一个Promise。返回的promise状态及返回值由then回调函数返回值决定。详情:点击这。因为返回了promise,所以可以被 链式调用

promise,then调用时序总结:promise容器的异步操作执行完毕,调用resolve/reject改变promise的状态,promise绑定的then()会在主堆栈结束后调用(主线程的时候then() 中的函数被置入了一个微任务队列)。then中的回调函数(onfulfilled /onrejected)执行后的返回的promise对象的状态及返回值由then回调函数(onfulfilled /onrejected)返回值决定。

<script>
    const resolvedProm = Promise.resolve(33);
    console.log(resolvedProm );

    setTimeout(() => {
        console.log('第三:',thenProm);
    });

    let thenProm = resolvedProm.then(value => {
        console.log("第二:在主堆栈结束后调用,优于任务进程。 接收和返回的值为:" + value);
        setTimeout(function() {
      		console.log("第五");
    	}, 1);
        return value;
    });

    console.log('第一:',thenProm);

    setTimeout(() => {
        console.log('第四',thenProm);
    });

    /* 上面的代码会依次打印出:
    Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33} 
    第一:Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined} 因为			resolvedProm异步调用then方法,同步时thenProm还未被赋值
    第二:在主堆栈结束后调用,优于其他任务进程。 接收和返回的值为:33
    第三:Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}
	第四:Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}
	第五
	*/
</script>
语法点3:catch()

catch() 方法返回一个Promise,并且处理拒绝的情况,用于promise组合中的错误处理。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。

p.catch(function(reason) {
//reason为拒绝的原因。
});

var p1 = new Promise(function(resolve, reject) {
  resolve('Success');
});

p1.then(function(value) {
  console.log(value); // "Success!"
  throw 'oh, no!';
}).catch(function(e) {
  console.log(e); // "oh, no!"
}).then(function(){
  console.log('catch()方法后面的链式继续执行');
}, function () {
  console.log('Not fired due to the catch');
});
/*打印结果
Success
oh, no!
catch()方法后面的链式继续执行
*/

注意:不被catch捕获的错误

// 在异步函数中抛出的错误不会被catch捕获到
var p2 = new Promise(function(resolve, reject) {
  setTimeout(function() {
    throw 'Uncaught Exception!';
  }, 1000);
});

p2.catch(function(e) {
  console.log(e); // 不会执行
});

// 在resolve()后面抛出的错误会被忽略
var p3 = new Promise(function(resolve, reject) {
  resolve();
  throw 'Silenced Exception!';
});

p3.catch(function(e) {
   console.log(e); // 不会执行
});

Promise.all() :详情点击

发起并行操作,然后等多个操作全部结束后进行下一步操作,如下:

var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
// expected output: Array [3, 42, "foo"]

promise解决了异步回调嵌套,使编写的代码扁平化。但是没有摆脱回调函数。

async/await

异步(async)函数是 ES7 的一个新的特性,它结合了 Promise,让我们摆脱 callback 的束缚,直接用类同步的“线性”方式,写异步函数。

async声明异步函数:

异步函数声明:只需在普通函数前添加一个关键字 async 即可.

返回值:async函数返回一个promise对象。返回的Promise对象会运行执行(resolve)异步函数的返回结果 (return)或者运行拒 绝(reject)——如果异步函数抛出异常的话。

单运行一个async函数:还是同步的运行

async function asynFunction(){  
	console.log('asynFunction begin');  

   	for (let index = 0; index < 2; index++) {  
     	console.log('asynFunction process ' + index);    
   	}  

   	console.log('asynFunction end');  
}  

console.log('1');  

console.log(asynFunction())

console.log('2');
/*打印顺序
1
asynFunction begin
asynFunction process 0
asynFunction process 1
asynFunction end
Promise {<resolved>: undefined} async函数返回一个promise对象,没有return则返回值为undefined
2
*/
await 堵塞作用:

用来等待异步执行结果的,阻塞await语句后面的代码,把异步改成一个同步的写法。

await在使用时,后面需要跟一个Promise对象,如果不是,会被转为Promise对象。

function b(arg){  
  return new Promise((resolve, reject) => {  
      resolve('你好,' + arg);  
    })  
}  

async function asynFunction(){  
  var aResult = await '中国';  
  var bResult = await b(aResult);  

  console.log(bResult);  
}  

console.log('1');  
asynFunction();  
console.log('2');
/*
1
2
你好,中国
*/
posted @ 2019-12-26 18:15  我来写BUG了  阅读(282)  评论(0编辑  收藏  举报