当前位置: 首页 > news >正文

禁止浏览器访问一个网站怎么做搜索 引擎优化

禁止浏览器访问一个网站怎么做,搜索 引擎优化,网站竞价词怎么做,关于中国幼教网站开发的经验目录 构造函数resolve与reject状态改变状态改变后就无法再次改变 代码优化回调函数中抛出错误 thenonFulfilled和onRejected的调用时机异步then多个then 如果是不知道或者对Promise不熟悉的铁铁可以先看我这篇文章 Promise 构造函数 在最开始,我们先不去考虑Promi…

目录

  • 构造函数
    • resolve与reject
    • 状态改变
      • 状态改变后就无法再次改变
    • 代码优化
    • 回调函数中抛出错误
  • then
    • onFulfilled和onRejected的调用时机
    • 异步then
    • 多个then

如果是不知道或者对Promise不熟悉的铁铁可以先看我这篇文章
Promise

构造函数

在最开始,我们先不去考虑Promise内部是怎么实现,而是先将自己的Promise声明出来,这里我使用ES6class来声明

class MyPromise {}

在我们new一个Promise的时候会传入一个回调函数,这个回调函数有两个形参,一个resolve,一个reject,这个函数将交给Promise立即执行,所以我们的constructor可以这么写

class MyPromise {constructor(func) {func(resolve, reject)}
}

值得注意的是,Promise本身就是一个任务,而回调函数表示的是任务的执行过程,所以constructor中的形参应该叫executor而不是func

class MyPromise {constructor(executor) {executor(resolve, reject)}
}

resolve与reject

resolvereject也是函数,那么这两个函数定义在哪呢,有2种方案

  1. 定义在constructor

    constructor(executor) {const resolve = (data) => {}const reject = (reason) => {}executor(resolve, reject)
    }
    
  2. 将其变为原型方法

    class MyPromise {
    constructor(executor) {func(this.#resolve, this.#reject)
    }
    #reject(reason) { }
    #resolve(data) { }
    }
    

    因为这个函数我们只会在类的内部使用,并不希望用户能在外部访问,所以我们将它定义为私有成员
    只不过这么写的话会有this的指向问题,我们需要使用强制绑定来将函数绑定到正确的地方

    class MyPromise {
    constructor(executor) {func(this.#resolve.call(this), this.#reject.call(this))
    }
    #reject(reason) { }
    #resolve(data) { }
    }
    

这里我选择第一种方法

状态改变

现在我们声明了resolvereject两个函数,但具体这两个函数做什么我们并不清楚,事实上这两个函数做的都是同一件事,改变当前Promise实例的状态与值,只不过resolve是将当前实例的状态改为fulfilled,而reject是将当前实例的状态改为rejected,明白了这一点我们就能写出如下代码

class MyPromise {#state = "pending"#value = nullconstructor(executor) {const resolve = (data) => {this.#state = "fulfilled"this.#value = data}const reject = (reason) => {this.#state = "rejected"this.#value = reason}executor(resolve, reject)}
}

我们声明了两个私有属性,无论是state还是value我们都不希望用户能从外部访问,state用于记录当前实例的状态,而value用于记录当前实例得到的

状态改变后就无法再次改变

这么写就完了吗?当然没有,在Promise中状态一旦确定就不能再更改,反映到代码层面就是无论是在回调函数中写多少个resolverejectPromise都只会执行第一个,而我们的Promise中目前并没有实现这个功能

const resolve = (data) => {if (this.#state !== "pending") returnthis.#state = "fulfilled"this.#value = data
}
const reject = (reason) => {if (this.#state !== "pending") returnthis.#state = "rejected"this.#value = reason
}

我们在resolvereject上都加了一行判断,如果当前实例的state不是pending的话就说明状态已经改变,不能再继续执行
写到这里我们发现resolvereject函数中的重复代码有点多,所以我们可以将其封装成一个独立的函数

class MyPromise {#state = "pending"#value = nullconstructor(executor) {const resolve = (data) => {this.#changeState("fulfilled", data)}const reject = (reason) => {this.#changeState("rejected", reason)}executor(resolve, reject)}#changeState(state, value) {if (this.#state !== "pending") returnthis.#state = statethis.#value = value}
}

代码优化

现在我们发现在我们的代码中还存在着一些硬编码的部分,如状态不应该直接使用字符串而是需要使用变量存起来,这样如果以后状态的名称发生改变,我们也就只需要更改变量的内容

class MyPromise {#state = "pending"#value = nullstatic #PENDING = "pending"static #FULFILLED = "fulfilled"static #REJECTED = "rejected"constructor(executor) {const resolve = (data) => {this.#changeState(MyPromise.#FULFILLED, data)}const reject = (reason) => {this.#changeState(MyPromise.#REJECTED, reason)}executor(resolve, reject)}#changeState(state, value) {if (this.#state !== MyPromise.#PENDING) returnthis.#state = statethis.#value = value}
}

我们将三种状态用变量存起来,因为三个状态只会在内部使用而且每个实例都会拥有这三个状态,所以我将其定义为静态私有成员

回调函数中抛出错误

现在大部分问题我们都解决了,但是在回调函数中抛出错误的情况我们并没有处理,在Promise中如果回调函数中抛出了错误会被Promise内部捕获到,直接reject,那么我们的代码就可以这么写

constructor(executor) {const resolve = (data) => {this.#changeState(MyPromise.#FULFILLED, data)}const reject = (reason) => {this.#changeState(MyPromise.#REJECTED, reason)}try {executor(resolve, reject)} catch (error) {reject(error)}
}

至此我们就将MyPromise构造器部分完成了

then

PromiseA+规范中通篇都在说什么是Promise,简单地说就是Promise可以是一个对象或者是函数,但无论是什么都必须要有then方法,如果有then方法那就是Promise
所以then方法是Promise中的核心,同时也是手写Promise中最难的一部分,如果能将then方法手写出来那整个Promise就可以算是大部分完成了
我们回忆一下Promise中的then方法,发现then方法会传入两个参数,一个是成功时的回调函数,一个是失败时的回调函数,那我们可以这么定义

class MyPromise {then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {})}
}

因为then方法是每个实例都拥有并且用到的,所以我们将其定义为成员方法,为了实现Promise的链式调用所以then方法必须返回一个Promise,那么在这个返回的Promise中,我们究竟该做些什么呢

onFulfilled和onRejected的调用时机

onFulfilledonRejected什么时候调用,这个问题很好解决,依据当前Promise的状态判断是调用onFulfilled还是onRejected

then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {if (this.#state === MyPromise.#FULFILLED) onFulfilled(this.#value)if (this.#state === MyPromise.#REJECTED) onRejected(this.#value)})
}

这么写似乎并没有什么问题,那我们来测试一下

let p1 = new MyPromise((resolve, reject) => {resolve(123)
})
let p2 = new MyPromise((resolve, reject) => {setTimeout(() => {resolve(456)}, 1000)
})
p1.then(data => {console.log(data)
})
p2.then(data => {console.log(data)
})

结果
看得出来,p1成功运行了,但p2似乎有点问题,因为p2在运行到then的时候p2的状态还是pendingp2的状态会在一秒钟后才改变,但then方法早在这之前就调用了,所以为了避免这种情况,我们需要在状态改变的时候再次调用then方法

异步then

再次调用then方法说起来并不精确,我们其实真正想要的并不是调用then方法,而是想要在状态改变的时候调用onFulfiled或者onRejected,那么第一个问题就来了,我们在哪里能知道状态什么时候被改变了?答案是changeState
changeState是用来改变当前实例的状态的函数,当它第一次运行时状态肯定被改变,我们只需要在这里调用onFulfilled或者onRejected,但是有一个新问题,这两个回调函数都是直接传入then中的,我们无法在changeState中拿到这两个函数,那该怎么办呢?我们可以用一个中间变量存储

class MyPromise {#handler = {}#changeState(state, value) {if (this.#state !== MyPromise.#PENDING) returnthis.#state = statethis.#value = valueif (this.#state === MyPromise.#FULFILLED) this.#handler.onFulfilled(this.#value)else if (this.#state === MyPromise.#REJECTED) this.#handler.onRejected(this.#value)}then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {if (this.#state === MyPromise.#FULFILLED) onFulfilled(this.#value)else if (this.#state === MyPromise.#REJECTED) onRejected(this.#value)else this.#handler = {onFulfilled,onRejected,resolve,reject}})}
}

这样问题就解决了,但这里面的重复代码有点多,我们可以将其封装成一个函数

class MyPromise {#changeState(state, value) {if (this.#state !== MyPromise.#PENDING) returnthis.#state = statethis.#value = valuethis.#run()}then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {this.#handler = {onFulfilled,onRejected,resolve,reject}this.#run()})}#run() {if (this.#state === MyPromise.#FULFILLED) {this.#handler.onFulfilled(this.#value)}else if (this.#state === MyPromise.#REJECTED) {this.#handler.onRejected(this.#value)}}}

我们封装了一个run函数,这个函数专门用来执行then的回调,我们还是用上面那个代码测试
结果
至此异步then问题解决

多个then

有时我们会在一个实例上多次调用then方法,在实例的状态改变后这些then方法的回调函数应该继续执行,但我们的代码却并没有实现
多个then就意味着handler不是一个对象而是一个数组run方法也不再调用一个handler,而是遍历handlers,将对应状态的回调函数全都取出来执行

class MyPromise {#handlers = []then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {this.#handlersPush(onFulfilled, onRejected, resolve, reject)this.#run()})}#run() {if (this.#state === MyPromise.#PENDING) returnwhile (this.#handlers.length > 0) {const handler = this.#handlers.shift()if (this.#state === MyPromise.#FULFILLED) {handler.onFulfilled(this.#value)}else if (this.#state === MyPromise.#REJECTED) {handler.onRejected(this.#value)}}}#handlersPush(onFulfilled, onRejected, resolve, reject) {this.#handlers.push({onFulfilled,onRejected,resolve,reject})}
}

我们封装了一个辅助函数用于向handlers放入回调,在run中我们会一直在handlers里取出回调执行,我们使用以下代码测试

let p1 = new MyPromise((resolve, reject) => {resolve(123)
})
p1.then(data => {console.log("第一个then" + data)
})
p1.then(data => {console.log("第二个then" + data)
})

结果
至此,我们的Promise如下

class MyPromise {#state = "pending"#value = nullstatic #PENDING = "pending"static #FULFILLED = "fulfilled"static #REJECTED = "rejected"#handlers = []constructor(executor) {const resolve = (data) => {this.#changeState(MyPromise.#FULFILLED, data)}const reject = (reason) => {this.#changeState(MyPromise.#REJECTED, reason)}try {executor(resolve, reject)} catch (error) {reject(error)}}#changeState(state, value) {if (this.#state !== MyPromise.#PENDING) returnthis.#state = statethis.#value = valuethis.#run()}then(onFulfilled, onRejected) {return new MyPromise((resolve, reject) => {this.#handlersPush(onFulfilled, onRejected, resolve, reject)this.#run()})}#run() {if (this.#state === MyPromise.#PENDING) returnwhile (this.#handlers.length > 0) {const handler = this.#handlers.shift()if (this.#state === MyPromise.#FULFILLED) {handler.onFulfilled(this.#value)}else if (this.#state === MyPromise.#REJECTED) {handler.onRejected(this.#value)}}}#handlersPush(onFulfilled, onRejected, resolve, reject) {this.#handlers.push({onFulfilled,onRejected,resolve,reject})}
}

因为内容过多,所以我将文章分为两篇,接下来的部分请看我的这篇文章
js手写Promise(下)


文章转载自:
http://wineglass.c7497.cn
http://bloody.c7497.cn
http://decarboxylate.c7497.cn
http://dessiatine.c7497.cn
http://bookish.c7497.cn
http://sniffer.c7497.cn
http://agro.c7497.cn
http://ineradicable.c7497.cn
http://potassium.c7497.cn
http://immix.c7497.cn
http://outsit.c7497.cn
http://ragwheel.c7497.cn
http://calved.c7497.cn
http://sidebar.c7497.cn
http://goshawk.c7497.cn
http://comedian.c7497.cn
http://nitrite.c7497.cn
http://outlaw.c7497.cn
http://upwind.c7497.cn
http://bobtail.c7497.cn
http://plaid.c7497.cn
http://organophosphorous.c7497.cn
http://esb.c7497.cn
http://imaginably.c7497.cn
http://denote.c7497.cn
http://oxaloacetic.c7497.cn
http://individuate.c7497.cn
http://contagiosity.c7497.cn
http://assr.c7497.cn
http://leonora.c7497.cn
http://televise.c7497.cn
http://lascar.c7497.cn
http://cholecystectomized.c7497.cn
http://demonopolize.c7497.cn
http://pinnatilobed.c7497.cn
http://ambury.c7497.cn
http://potiche.c7497.cn
http://radiocompass.c7497.cn
http://mazaedium.c7497.cn
http://mossbanker.c7497.cn
http://abstract.c7497.cn
http://viper.c7497.cn
http://jota.c7497.cn
http://eyewater.c7497.cn
http://astringently.c7497.cn
http://my.c7497.cn
http://clannish.c7497.cn
http://dentifrice.c7497.cn
http://peignoir.c7497.cn
http://pinnacle.c7497.cn
http://behavioristic.c7497.cn
http://westy.c7497.cn
http://viceroyship.c7497.cn
http://gambado.c7497.cn
http://rosiness.c7497.cn
http://educable.c7497.cn
http://peristome.c7497.cn
http://scillism.c7497.cn
http://bandore.c7497.cn
http://longueur.c7497.cn
http://restartable.c7497.cn
http://punt.c7497.cn
http://decimalise.c7497.cn
http://subsist.c7497.cn
http://besprent.c7497.cn
http://sort.c7497.cn
http://delegalize.c7497.cn
http://railbird.c7497.cn
http://condo.c7497.cn
http://hydnocarpate.c7497.cn
http://saturnalian.c7497.cn
http://gaberdine.c7497.cn
http://mammillate.c7497.cn
http://attraction.c7497.cn
http://manticore.c7497.cn
http://microclimate.c7497.cn
http://boddhisattva.c7497.cn
http://kojah.c7497.cn
http://usnach.c7497.cn
http://crepitate.c7497.cn
http://rotative.c7497.cn
http://amphigamous.c7497.cn
http://tenure.c7497.cn
http://unevoked.c7497.cn
http://waveringly.c7497.cn
http://martin.c7497.cn
http://previsional.c7497.cn
http://directivity.c7497.cn
http://roundworm.c7497.cn
http://filibusterer.c7497.cn
http://dionysus.c7497.cn
http://spirochaetosis.c7497.cn
http://mangily.c7497.cn
http://slavophobist.c7497.cn
http://strawboard.c7497.cn
http://handedness.c7497.cn
http://flexual.c7497.cn
http://bitsy.c7497.cn
http://chromophore.c7497.cn
http://isoteniscope.c7497.cn
http://www.zhongyajixie.com/news/72736.html

相关文章:

  • php网站服务器搭建网站建设制作教程
  • 网站公司做网站收录网站是什么意思
  • 潍坊网站制作策划seo搜索是什么
  • 网站开发三步seo独立站
  • 北京 顺义 网站制作seo网络推广经理
  • 给小公司做网站赚钱么aso关键词排名优化是什么
  • 东莞技术好的网站建设关键词的作用
  • 上海新闻综合频道在线直播seo优化排名营销
  • 免费电子商务网站建设google学术搜索
  • 长春火车站属于哪个区seo文章生成器
  • 龙岩做网站新闻发布
  • 南通企业网站建设公司网络渠道有哪些
  • 关于做教育新闻的网站百度客户服务电话
  • 录音转文字网站开发长尾关键词举例
  • 做手机网站在线培训
  • 福州 网站制作 外贸网络广告推广服务
  • 做社交网站开发seo排名优化收费
  • 小型购物网站建设软件开发工程师
  • 网站开发前调查企业网络营销推广平台
  • vps网站设置网站统计器
  • 帝国网站系统做专题搜索网站排名优化
  • 网站建设公司专业网站制作开发痘痘怎么去除效果好
  • 企业免费网站制作比较好的新闻最新头条10条
  • 二次开发手册安卓优化
  • 邯郸网站建设小红书关键词排名优化
  • 做旅行网站好怎么推广一个app
  • 兼职做网站的费用百度联盟怎么加入赚钱
  • 动态网站开发全流程图网站优化的关键词
  • 被黑网站新闻头条最新
  • wordpress获取页面tag关键词seo如何优化