JS异步解决方案

一 回调函数

异步操作的最基本方法是回调函数

ajax(urlString, callback){
	//回调函数执行前操作
	callback()
}

callback(){
	//处理逻辑
}

但是容易造成回调地狱

ajax(url, () => {
    // 处理逻辑
    ajax(url1, () => {
        // 处理逻辑
        ajax(url2, () => {
            // 处理逻辑
        })
    })
})

并且回调函数高度耦合,程序结构混乱,不能使用 try catch 捕捉错误,不能直接return

二 Promise

Promise状态

promise对象有三种状态

  • pending——Promise对象实例创建时候的初始状态
  • Fulfiied—— Promise对象成功执行后的状态
  • Rejected——Promise对象失败后的状态

promise 构造器函数

promise的构造器函数接受一个函数做为参数,该函数的两个参数为resolve和reject,异步操作成功后,调用 resolve 函数,将promise对象的状态从 pending 转化为 Fulfied ,失败则调用 reject 函数 将状态 pending 转化为 rejected

const promise = new Promise(function(resolve, reject) {
  // code 
  if (// 异步操作成功 //){
    resolve(value);
  } else {
    reject(error);
  }
});

promise的链式调用

Promise.prototype.then()

Promise中then方法是定义再原型对象Promise.prototye上的,then() 方法有两个参数,一个是resolved状态的回调函数,一个是rejected状态的回调函数

promise.then(function(value){
	console.log(value);
},function(err){
	console.log(err);
})

Promise.prototype.catch()

异步操作抛出错误时,状态变为rejected,调用catch()指定的回调函数,也就是被catch() 方法捕获

const promise = new Promise(function(resolve, reject) {
  throw new Error('test');
});
promise.catch(function(error) {
  console.log(error);
});
// Error: test

Promise.prototype.finally()

与try catch中finally类似,不管Promise对象状态如何,都会进入finally中

Promise.all()

该方法可以将多个Promise实例转化为一个新的Promise实例

const p = Promise.all([p1, p2, p3]);

此时p的状态由 p1 p2 p3 共同决定

  • p1 p2 p3 状态全为fulfilled, p的状态才会变成fulfilled,此时p的状态才会为 fulfilled,p1 p2 p3的返回值会组成一个数组传递给p的回调函数
  • p1 p2 p3 中只要一个状态为rejected,p的状态会变为 rejected。其中第一个为rejected的实例的返回值传递给p的回调函数
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
  return getJSON('/post/' + id + ".json");
});

Promise.all(promises).then(function (posts) {
  // ...
}).catch(function(reason){
  // ...
});

手写简易promise.all()

function all(arr){
	return new Promise(res,rej){
		const result = [];
		const resNum = 0;
		const length = arr.erngth
		if(length==0) return new Promise(arr);
		arr.forEach(item=>{
			item.then(resolve=>{
				result.push(resolve);
				count++;
				if(count == length){  //全为fullfied 返回结果
					res(result);
				}
			}).catch(err=>{
				rej(err);
			})
		})
	}
}

promise.race()

p1、p2、p3之中第一个改变状态的,p的状态就跟着其改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

const p = Promise.race([p1, p2, p3]);

Generators/yield

Generators可以控制函数的执行,是一种状态机,封装了多个内部状态

  • Generators还是一个遍历器对象生成函数
  • yield可暂停函数,next可启动函数,每次返回的时yield后的表达式结果
  • yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值
function* funG() {
  yield console.log(1)
  yield console.log(2)
  yield console.log(3)
}

function run() {
  console.log(4)
}

const iter = funG()
iter.next()
run()
iter.next()
iter.next()
iter.next()

// 结果:
1
4
2
3
{value: undefined, done:true}

异步解决

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){
    console.log(e);
  }
  return y;
}

var g = gen(1);
g.next();
g.throw('出错了');

async/await

async 为Generator函数的语法糖
经典例子:

const fs = require('fs');

const readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) return reject(error);
      resolve(data);
    });
  });
};

const gen = function* () {
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

const asyncReadFile = async function () {
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

async函数是Generator函数 * 号变成 async,将yield换成await,另外也有许多特点

  • async自带执行器,直接与普通函数一样执行即可,Generator函数必须依靠执行器
  • async 返回Promise对象 ,再使用await可以返回该Promise对象结果而Generator函数返回Iterator对象

原理

async 函数就是将Generator 函数和自动执行器,包装在一个函数里

async function fn(args) {
  // ...
}

// 等同于

function fn(args) {
  return spawn(function* () {
    // ...
  });
}

spawn函数是自动执行器的翻版

function spawn(genF) {
  return new Promise(function(resolve, reject) {
    const gen = genF();
    function step(nextF) {
      let next;
      try {
        next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值