当前位置: 代码迷 >> 综合 >> Promise,generator,async和await,callback 事件循环机制
  详细解决方案

Promise,generator,async和await,callback 事件循环机制

热度:31   发布时间:2023-11-26 04:47:36.0

1、回调函数:

回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调。

function a(callback){alert("这是first函数a");var x =1;var y=2;return callback(x,y);}function b(x,y){alert("这是回调函数b");return x+y;}$(function(){var result = a(b);alert("result = "+ result);});
//这是first函数a,这是回调函数bresult = 3//这里函数首先执行了first函数a,之后调用了回调函数b,最后返回函数a的返回值。

回调种类:同步回调、异步回调

回调可以是同步的

function a(fn) {fn();
};a(funtion() {console.log('I am callback, but not async'); // step1
});
console.log(end);// step2

回调缺点:

  1. 高耦合,维护困难,回调地狱;
  2. 每个任务只能指定一个回调函数;
  3. 如果几个异步操作之间并没有顺序之分,同样也要等待上一个操作执行结束再进行下一个操作。

 2、promise

ES6给我们提供了一个原生的构造函数Promise,Promise代表了一个异步操作,可以将异步对象和回调函数脱离开来,通过.then方法在这个异步操作上绑定回调函数,Promise可以让我们通过链式调用的方法去解决回调嵌套的问题,而且由于promise.all这样的方法存在,可以让同时执行多个操作变得简单。

promise对象存在三种状态:

  1. Fulfilled:成功状态
  2. Rejected:失败状态
  3. Pending:既不是成功也不是失败状态,可以理解为进行中状态

Promise的缺点:

  1. 当处于未完成状态时,无法确定目前处于哪一阶段。
  2. 如果不设置回调函数,Promise内部的错误不会反映到外部。(resolve就是回调函数)
  3. 无法取消Promise,一旦新建它就会立即执行,无法中途取消。

promise的all,数组中三个数,其中两个正常,一个会报错,怎么让正常的两个返回

由于Promise.all(request).then(…).catch(…) 会在所有requestresolve时才会进then方法,并且把所
有结果以一个数组返回,只要有一个失败,就会进catch。而如果在单个请求中定义了catch方法,那么就
不会进Promise.allcatch方法。因此,可以在单个的catch中对失败的promise请求做处理,可以使
成功的请求正常返回。

 ①Promise then reject了,后面的catch会执行吗?(会)②Promise Catch后面的then还是会执行?(会)

catch()是then()的语法糖。then()返回的是一个promise。 因为then()和catch()又返回了一个promise,因此,后续调用可以串联起来。then()的两个参数函数中返回的值,会自动包装成一个已resolved的promise。

function test(res) {return Promise.resolve(res).then(res => {console.log(res += '!');return res;}).then(res => {console.log(res += '!');return Promise.reject("end"); //此处返回了一个新的promise}).catch(res => {console.log(res);return res;  //此处也返回了一个新的resolved的promise}).then(res => {console.log(res += '!');  //肯定会执行了});
}
test('hello');

 

function test(res) {//创建一个rejected状态的Promisereturn Promise.reject(res).then(res => {   //此处不会执行!!!console.log(res += '!');return res;}).catch(res => {console.log(res);return res;  //catch执行完后,返回了一个新的Fulfilled的状态的Promise,
//等同于return Promise.resolve(res);所以后面的then会执行,而catch就不会执行了。}).then(res => {console.log(res += '!');  }) .catch(res => {console.log(res+"?");return res;  });
}
test('hello').then((res) =>{//test方法中将错误统一栏截处理了,可以不返回内容,//然后此处判断res来确定要不要执行!!
});

 可以将非函数参数传递给Promise.then()而不会导致错误?

将非函数参数传递给Promise.then()不会导致错误,then(不是回调函数)也不会进入微任务队列,直接执行(同步)

3、 generator原理

Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态,但是只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。

必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句,如果没有return语句,就执行到函数结束)为止。yield表达式是暂停执行的标记,而next方法可以恢复执行。

function* gen(x) {console.log('start')const y = yield x * 2return y
}const g = gen(1)
g.next()   // start { value: 2, done: false }
g.next(4)  // { value: 4, done: true }

 

  • gen()? 不会立即执行,而是一上来就暂停,返回一个 ?Iterator ?对象(具体可以参考 Iterator遍历器)
  • 每次? g.next() ?都会打破暂停状态去执行,直到遇到下一个? yield ?或者 ?return?
  • 遇到? yield ?时,会执行 ?yeild? 后面的表达式,并返回执行之后的值,然后再次进入暂停状态,此时? done: false?。
  • ?next? 函数可以接受参数,作为上个阶段异步任务的返回结果,被函数体内的变量接收
  • 遇到? return ?时,会返回值,执行结束,即 ?done: true?
  • 每次? g.next() ?的返回值永远都是 ?{value: ... , done: ...} ?的形式

如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。

如果该函数没有return语句,则返回的对象的value属性值为undefined

 Generator函数暂停恢复执行原理:协程、执行器(Generator 是一个异步操作的容器。它的自动执行需要一种机制,当异步操作有了结果,能够自动交回执行权。

4、async和await

await后面的表达式是从右到左运行的。await针对所跟不同表达式的处理方式:

  • Promise 对象:await 会暂停执行,等待 Promise 对象 resolve,然后恢复 async 函数的执行并返回解析值。
  • 非 Promise 对象:直接返回对应的值。

async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。为什么会暂停执行,原理是什么?

async/await

async 是Generator函数的语法糖,并对Generator函数进行了改进,是对 yield 的简单封装

async函数对 Generator 函数的改进,体现在以下四点:

  1. 内置执行器。Generator 函数的执行必须依靠执行器,而 async 函数自带执行器,无需手动执行 next() 方法。

  2. 更好的语义。async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。

  3. 更广的适用性。co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。

  4. 返回值是 Promise。async 函数返回值是 Promise 对象,比 Generator 函数返回的 Iterator 对象方便,可以直接使用 then() 方法进行调用。

 重点是自带了执行器,相当于把我们要额外做的(写执行器/依赖co模块)都封装了在内部

await后面的函数执行完毕时,await会产生一个微任务(Promise.then是微任务)。但是我们要注意这个微任务产生的时机,它是执行完await之后,直接跳出async函数,执行其他代码。其他代码执行完毕后,再回到async函数去执行剩下的代码,然后把await后面的代码注册到微任务队列当中

五、事件循环机制,两者有区别:

浏览器环境下:当主代码微任务执行完毕,开始执行宏任务,这时宏任务中有微任务时,会马上执行微任务再执行其他的宏任务。

nodejs:当宏任务中有微任务时,会先将微任务放到微任务队列中,执行完宏任务再执行微任务。

  相关解决方案