《深切明白ES6》笔记—— Promise与异步编程(11)

为何要异步编程

我们在写前端代码时,常常会对dom做事宜处置惩罚操纵,比方点击、激活核心、落空核心等;再比方我们用ajax要求数据,运用回调函数猎取返回值。这些都属于异步编程。

或许你已也许晓得JavaScript引擎单线程的观点,那末这类单线程形式和异步编程有什么关系呢?

JavaScript引擎中,只需一个主线程,当实行JavaScript代码块时,不允许其他代码块实行,而事宜机制和回调机制的代码块会被添加到使命行列(或许叫做客栈)中,当相符某个触发还调或许事宜的时候,就会实行该事宜或许回调函数。

上面这段话的意义能够如许明白,假定你是一个修仙者,你去闯一个秘境,这个秘境就是主线程,你只能一向深切下去,直到找到宝贝和出口,而你另有一个自身的储物空间,这个空间就相似客栈,你在储物空间放了许多你能够用到的宝贝或许丹药,这些东西就是回调函数和事宜函数,当你碰到风险或许满足某个前提时,就可以够从储物空间拿出你当前须要的东西。

好吧,不扯这么远,下面看正题。

事宜模子:
浏览器首次衬着DOM的时候,我们会给一些DOM绑定事宜函数,只需当触发了这些DOM事宜函数,才会实行他们。

const btn = document.querySelector('.button')
btn.onclick = function(event) {
  console.log(event)
}

回调形式:
nodejs中能够异常罕见这类回调形式,然则关于前端来讲,ajax的回调是最熟习不过了。ajax回调有多个状况,当相应胜利和失利都有差别的回调函数。

$.post('/router', function(data) {
  console.log(data)
})

回调也能够带来一个题目,那就是地狱回调,不过荣幸的是,我从进入前端界最先,就运用react,跳过了许多坑,特别是地狱回调,一向没有机会在工作中遇见到,真是遗憾。

Promise

事宜函数没有题目,我们用的很爽,题目出在回调函数,尤其是指地狱回调,Promise的涌现恰是为了防止地狱回调带来的搅扰。

引荐你看JavaScript MDN Promise教程,然后再连系本文看,你就可以学会运用Promise了。

Promise是什么

Promise的中文意义是许诺,也就是说,JavaScript对你许下一个许诺,会在将来某个时候兑现许诺。

Promise生命周期

react有生命周期,vue也有生命周期,就连Promise也有生命周期,如今生命周期咋这么流行了。

Promise的生命周期:进行中(pending),已完成(fulfilled),谢绝(rejected)

Promise被称作异步效果的占位符,它不能直接返回异步函数的实行效果,须要运用then(),当猎取异常回调的时候,运用catch()。

此次我们运用axios插件的代码做例子。axios是前端比较热点的http要求插件之一。

1、建立axios实例instance。

import axios from 'axios'
export const instance = axios.create()

2、运用axios实例 + Promise猎取返回值。

const promise = instance.get('url')

promise.then(result => console.log(result)).catch(err => console.log(err))

运用Promise构建函数建立新的Promise

Promise组织函数只需一个参数,该参数是一个函数,被称作实行器,实行器有2个参数,分别是resolve()和reject(),一个示意胜利的回调,一个示意失利的回调。

new Promise(function(resolve, reject) {
  setTimeout(() => resolve(5), 0)
}).then(v => console.log(v)) // 5

记着,Promise实例只能经由过程resolve或许reject函数来返回,而且运用then()或许catch()猎取,不能在new Promise内里直接return,如许是猎取不到Promise返回值的。

1、我们也能够运用Promise直接resolve(value)。

Promise.resolve(5).then(v => console.log(v)) // 5

2、也能够运用reject(value)

Promise.reject(5).catch(v => console.log(v)) // 5

3、实行器毛病经由过程catch捕捉。

new Promise(function(resolve, reject) {
  if(true) {
    throw new Error('error!!')
  }
}).catch(v => console.log(v.message)) // error!!

全局的Promise谢绝处置惩罚

不主要的内容,不必细看。

这里涉及到nodejs环境和浏览器环境的全局,主要说的是假如实行了Promise.reject(),浏览器或许node环境并不会强迫报错,只需在你挪用catch的时候,才晓得Promise被谢绝了。

这类行动就像是,你写了一个函数,函数内部有true和false两种状况,而我们愿望false的时候抛出毛病,然则在Promise中,并不能直接抛出毛病,不管Promise是胜利照样谢绝状况,你猎取Promise生命周期的要领只能经由过程then()和catch()。

nodejs环境:

node环境下有个对象叫做process,纵然你没写过后端node,假如写过前端node服务器,也应当晓得能够运用process.ENV_NODE猎取环境变量。为了监听Promise的reject(谢绝)状况,NodeJS供应了一个process.on(),相似jQuery的on要领,事宜绑定函数。

process.on()有2个事宜

unhandledRjection:在一个事宜轮回中,当Promise实行reject(),而且没有供应catch()时被挪用。

一般状况下,你能够运用catch捕捉reject。

Promise.reject("It was my wrong!").catch(v => console.log(v))

然则,有时候你不老是记得运用catch。你就须要运用process.on()

let rejected
rejected = Promise.reject("It was my wrong!")

process.on("unhandledRjection", function(reason, promise) {
  console.log(reason.message) // It was my wrong!
  console.log(rejected === promise) // true
})

rejectionHandled:在一个事宜轮回后,当Promise实行reject,而且没有供应catch()时被挪用。

let rejected
rejected = Promise.reject(new Error("It was my wrong!"))

process.on("rejectionHandled", function(promise) {
  console.log(rejected === promise) // true
})

异同:

事宜轮回中、事宜轮回后,你能够很难明白这2个的区分,然则这不主要,主要的是,假如你经由过程了catch()要领来捕捉reject操纵,那末,这2个事宜就不会见效。

浏览器环境:

和node环境一样,都供应了unhandledRjection、rejectionHandled事宜,差别的是浏览器环境是经由过程window对象来定义事宜函数。

let rejected
rejected = Promise.reject(new Error("It was my wrong!"))

window.rejectionHandled = function(event) {
  console.log(event) // true
}
rejectionHandled()

将代码在浏览器控制台实行一遍,你就会发明报错了:Uncaught (in promise) Error: It was my wrong!

耶,你胜利了!报错内容恰是你写的reject()要领内里的毛病提醒。

Promise链式挪用

这个例子中,运用了3个then,第一个then返回 s * s,第二个then捕捉到上一个then的返回值,末了一个then直接输出end。这就叫链式挪用,很好明白的。我只运用了then(),现实开辟中,你还应当加上catch()。

new Promise(function(resolve, reject) {
try {

resolve(5)

} catch (error) {

reject('It was my wrong!!!')

}
}).then(s => s * s).then(s2 => console.log(s2)).then(() => console.log(‘end’))
// 25 “end”

Promise的其他要领

在Promise的组织函数中,除了reject()和resolve()以外,另有2个要领,Promise.all()、Promise.race()。

Promise.all():

前面我们的例子都是只需一个Promise,如今我们运用all()要领包装多个Promise实例。

语法很简朴:参数只需一个,可迭代对象,能够是数组,或许Symbol范例等。

Promise.all(iterable).then().catch()

示例:传入3个Promise实例

Promise.all([
  new Promise(function(resolve, reject) {
    resolve(1)
  }),
  new Promise(function(resolve, reject) {
    resolve(2)
  }),
  new Promise(function(resolve, reject) {
    resolve(3)
  })
]).then(arr => {
  console.log(arr) // [1, 2, 3]
})

Promise.race():语法和all()一样,然则返回值有所差别,race依据传入的多个Promise实例,只需有一个实例resolve或许reject,就只返回该效果,其他实例不再实行。

照样运用上面的例子,只是我给每一个resolve加了一个定时器,终究效果返回的是3,由于第三个Promise最快实行。

Promise.race([
  new Promise(function(resolve, reject) {
    setTimeout(() => resolve(1), 1000)
  }),
  new Promise(function(resolve, reject) {
    setTimeout(() => resolve(2), 100)
  }),
  new Promise(function(resolve, reject) {
    setTimeout(() => resolve(3), 10)
  })
]).then(value => {
  console.log(value) // 3
})

Promise派生

派生的意义是定义一个新的Promise对象,继续Promise要领和属性。

class MyPromise extends Promise {

  //从新封装then()
  success(resolve, reject) {
    return this.then(resolve, reject)
  }
  //从新封装catch()
  failer(reject) {
    return this.catch(reject)
  }
}

接着我们来运用一下这个派生类。


new MyPromise(function(resolve, reject) {
  resolve(10)
}).success(v => console.log(v)) // 10

假如只是派生出来和then、catch一样的要领,我想,你不会干这么无聊的事变。

Promise和异步的联络

Promise自身不是异步的,只需他的then()或许catch()要领才是异步,也能够说Promise的返回值是异步的。一般Promise被运用在node,或许是前端的ajax要求、前端DOM衬着递次等处所。

比Promise更牛逼的异步计划

在本章你只须要相识有async这个将来的计划,引荐不会的赶忙去网上找材料学,横竖我是已在现实项目中周全展开async了。

async function a() {
    await function() {}}
}

总结

Promise是什么、怎样用、怎样猎取返回值?是本章的中心内容,多看几遍,你会发明运用Promise是异常简朴的事变。

=> 返回文章目次

    原文作者:二月
    原文地址: https://segmentfault.com/a/1190000010444236
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞