异步编辑Promise

204 阅读4分钟

观看《ECMAScript异步编程》公开课


js 是单线程工作方式。碰见耗时的任务,开新的线程处理。结束后通知主线程,这就是异步

  • 异步:处理耗时任务不会影响主线程的其他效果

    ​ 回调函数,ajax,setTimeout, setInterval, promise, async/await

  • 同步:会等待耗时任务完成后在继续,会影响主线程的js(所有js效果都会等待)

  • 回调地狱(callback hell): 回调函数一个接着一个,有依赖关系。

回调地狱对于程序员非诚不友好,阅读困难,修改困难,对于 ”需要A和B都请求成功后在请求C“ (A + B => C) 这个操作很难有好的解决方案

Promise

promise是构造函数。构建一个异步处理对象。是异步编程的一种解决方案,js原生提供。

  • 三种状态(需要程序员手动设置状态):pending,fulfilled(resolve),rejected
  • 状态一旦改变,就不会再变
  • 对象状态不受外界影响
  • promise新建后回立即执行
new Promise((resolve, reject)=>{ // resolve/reject 是函数,用于设置状态
	// 要执行的异步任务
})
	.then( // promise处理完任务后,执行的操作
			()=>{} // resolve 成功时调用
		 ,()=>{} // reject 失败时调用
	)

promise没有改变异步操作本质,只是改变了代码结构,由嵌套改为链式调用

Promise 的值

resolve/reject 可以给then函数传递值

  • resolve 将异步操作的结果作为参数传递
  • reject 将异步操作的错误作为参数传递
1. 如下代码将打印什么值
new Promise((resolve, reject)=>{ 
	reject()
})
	.then( 
			()=>{ console.log('resolve', 1) } 
		 ,()=>{ console.log('reject', 2) }
	)
	.then( 
			()=>{ console.log('resolve', 3) } 
		 ,()=>{ console.log('reject', 4) }
	)

上面的代码将会打印 2,3 原因如下:

then方法返回的是一个新的promise,之后的then要取决于前一个then返回的是什么状态的promise

  • 如果then没有参数,则向上找,返回继承状态的promise
  • 如果then有参数(几个无所谓),则返回resolve状态的promise
  • 可以手动设置promise的状态
2. 手动返回
new Promise((resolve, reject)=>{ 
	reject()
})
	.then( 
			()=>{ console.log('resolve', 1) } 
		 ,()=>{ 
		 		console.log('reject', 2)
     		return new Promise((resolve, reject)=>{ 
          reject()
        })
     }
	)
	.then( 
			()=>{ console.log('resolve', 3) } 
		 ,()=>{ console.log('reject', 4) }
	)
	// 2, 4

catch

promise不易终止,所以会出现第一段代码的问题,失败后还会继续请求。 使用catch可以部分的解决问题。

  • 使用catch 进行统一捕获错误,但是优先级低于then的第二个参数。
  • catch返回一个成功的promise对象。所以catch之后的then会执行一参 resolve()。

Promise.all()

用于解决 ”需要A和B都请求成功后在请求C“ (A + B => C) 这个操作的解决方案

let p1 = new Promise((resolve, reject)=>{ ... })
let p2 = new Promise((resolve, reject)=>{ ... })
Promise.all([p1, p2]) // 数组中的多个promise都结束后执行then
	.then(arr => { ... }) // arr 是多个promise的返回值

Promise.race()

竞争:用于解决 ”A和B谁先请求成功(改变状态)则用返回值请求C“ (A || B => C) 这个操作的解决方案

let p1 = new Promise((resolve, reject)=>{ ... })
let p2 = new Promise((resolve, reject)=>{ ... })
Promise.race([p1, p2]) // 数组中的多个promise谁先改变状态,则用返回值执行then
	.then(val => { ... }) // val 是最先改变状态的promise的返回值

Promise.resolve() 和 Promise.reject()

Promise.resolve() 返回一个新的promise, 状态为resolve

Promise.reject() 返回一个新的promise, 状态为reject

.then( 
  ()=>{ console.log('resolve', 1) } 
  ,()=>{ 
    console.log('reject', 2)
    return Promise.reject('出错了') 
  }
)
Promise.reject('出错了') === new Promise((resolve, reject)=>{  reject()  })

async/await

async 函数返回一个promise对象

async函数返回的promise对象,必须等到内部的所有await命令后的promise对象执行完后才会发生状态改变。除非遇到return语句或者刨除错误

async function fn(){
 	try{
    var a = getawait(10)
    var b = getawait(10)
    console.log( ... )
	} catch(e){
		console.log(e)
	}
}
function getawait(v){
	return new Promise((resolve, reject)=>{ 
  	setTimeout(()=> {
      resolve(v*2)
    },2000)
  })
	
}
fn()

try/catch

try/catch/finally 语句用于处理代码中可能出现的错误信息。

错误可能是语法错误,通常是程序员造成的编码错误或错别字。也 可能是拼写错误或语言中缺少的功能(可能由于浏览器差异)。

try 语句允许我们定义在执行时进行错误测试的代码块。

catch 语句允许我们定义当 try 代码块发生错误时,所执行的代码块。

finally 语句在 try 和 catch 之后无论有无异常都会执行。

注意: catch 和 finally 语句都是可选的,但你在使用 try 语句时必须至少使用一个。

提示: 当错误发生时, JavaScript 会停止执行,并生成一个错误信息。使用 throw 语句 来创建自定义消息(抛出异常)。如果你将 throwtrycatch一起使用,就可以控制程序输出的错误信息。

throw

throw 语句抛出一个错误。

当错误发生时, JavaScript 会停止执行并抛出错误信息。

描述这种情况的技术术语是:JavaScript 将抛出一个错误。

throw 语句创建自定义错误。

技术术语是: 抛出异常

异常可以是 JavaScript 字符串、数字、逻辑值或对象:

throw new Error("为空")
throw "不是一个数字";