你们好,我是雷锋蜀黍。一直在某些面试宝典看到面试官要你手撸一个promise,今每天气这么好,不如咱们来搞一搞。(PS:从未看过别人的实现,本文更像是记录一个思考的过程)web
最终的代码彻底符合Promise A+规范,并经过全部 promises-aplus-tests
测试用例。先上个测试经过图得瑟一下,嘿嘿嘿。面试
若是本身动手实现过Promise的能够直接跳到 从零开始的Promise 章节,看看个人实现,下面咱们开始吧。数组
先回想一下promise是个啥:promise是为了解决回调地狱而出现的产物,经过实例的then、catch方法进行链式调用。它自己拥有三种状态:等待、成功、失败,而且成功失败后状态没法改变。通常使用方式:promise
new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(1)
}, 1000)
})
.then(function (res) {
console.log(res) // 1
return res
})
.catch(function (res) { // 不会被调用
console.log(res)
return res
})
复制代码
浏览器打印:浏览器
从中咱们能够看到实例上具备[[PromiseStatus]]
与[[PromiseValue]]
两个属性,分别表明状态与值。数据结构
隐式原型上具备catch、finally、then方法。闭包
先照上面分析的打个样:app
let MyPromise = (function () {
function resolve(res) {
this['[[PromiseStatus]]'] = 'fulfilled'
this['[[PromiseValue]]'] = res
}
function reject(res) {
this['[[PromiseStatus]]'] = 'rejected'
this['[[PromiseValue]]'] = res
}
return function (fn) {
this['[[PromiseStatus]]'] = 'pending'
this['[[PromiseValue]]'] = undefined
fn(resolve.bind(this), reject.bind(this))
}
})()
MyPromise.prototype.then = function (fn) {
// 只有在成功状态才会调用
if (this['[[PromiseStatus]]'] === 'fulfilled') {
this['[[PromiseValue]]'] = fn(this['[[PromiseValue]]'])
}
// 返回自身 进行链式调用
return this
}
MyPromise.prototype.catch = function (fn) {
// 只有在失败状态才会调用
if (this['[[PromiseStatus]]'] === 'rejected') {
this['[[PromiseValue]]'] = fn(this['[[PromiseValue]]'])
}
// 返回自身 进行链式调用
return this
}
复制代码
试着打印输出:异步
let a = new MyPromise(function (resolve, reject) {
setTimeout(function () {
resolve(1)
}, 1000)
}).then(function (res) {
console.log(res)
return 2
}).catch(function (res) {
console.log(res)
return 3
})
console.log(a)
复制代码
emmm,把异步的问题忘记了,在setTimeout期间状态一直是pending,因此直接调用then是无效的。思路应该是把这些then中的方法进行存储,在resolve结束时进行调用。async
咱们建立个属性进行链式函数的存储,须要注意的是存在成功和失败两种状态。
let MyPromise = (function () {
function resolve(res) {
this['[[PromiseStatus]]'] = 'fulfilled'
this['[[PromiseValue]]'] = res
// 模拟异步 并保证接收到全部then方法后执行
setTimeout(() => {
// 遍历finishArr并链式执行
while (this.asyncArr.finishArr.length > 0) {
this.asyncArr.finishArr.shift()()
}
}, 0);
// 干掉永远不可能执行的方法
this.asyncArr.errorArr = []
}
function reject(res) {
this['[[PromiseStatus]]'] = 'rejected'
this['[[PromiseValue]]'] = res
setTimeout(() => {
// 遍历errorArr并链式执行
while (this.asyncArr.errorArr.length > 0) {
this.asyncArr.errorArr.shift()()
}
}, 0);
// 干掉永远不可能执行的方法
this.asyncArr.finishArr = []
}
return function (fn) {
this['[[PromiseStatus]]'] = 'pending'
this['[[PromiseValue]]'] = undefined
this.asyncArr = { // 保存链式调用的方法
finishArr: [],
errorArr: []
}
fn(resolve.bind(this), reject.bind(this))
}
})()
MyPromise.prototype.then = function (fn) {
// 失败时直接返回 等待和成功都要压入数组中
if( this['[[PromiseStatus]]'] === 'rejected') return this
this.asyncArr.finishArr.push( ()=> {
this['[[PromiseValue]]'] = fn(this['[[PromiseValue]]'])
})
// 返回自身 进行链式调用
return this
}
MyPromise.prototype.catch = function (fn) {
if( this['[[PromiseStatus]]'] === 'fulfilled') return this
this.asyncArr.errorArr.push( ()=> {
this['[[PromiseValue]]'] = fn(this['[[PromiseValue]]'])
})
// 返回自身 进行链式调用
return this
}
复制代码
欧凯~这样就解决了异步的问题,也彻底知足咱们经常使用的几个功能。可是你们以为这就结束了吗?不,这只是开始,仍是个错误的开始。
下面咱们一块儿来总结下上面的代码在逻辑上存在哪些错误
可能有人就疑惑了,promise的状态原本就是不能被改变的,这没有错啊。那请你来看下面这段代码:
let a = new Promise(function (resolve, reject) {
reject(1)
})
.catch(function (res) {
console.log(res)
return 3
})
.then(function (res) {
console.log(res)
})
console.log(a) // type: resolved val: undefined
复制代码
你会发现a的状态从reject
变为了resolved
,你是否会动摇对promise的认知呢,就以为别人说的什么promise不能改变状态都是扯淡,能变得。
切勿听风是雨,本身动手试一下才会真的明白。 then方法返回的并非当前对象自身,而是一个全新的Promise。
如今咱们将全部的then、catch方法都存放到了第一个promise的属性上,那若是按照上一条的改进意见,每次都返回一个全新的promise,那这种方式是否可行呢?答案我想是能够的,可是这样并很差,会形成头重脚轻,首个promise对象与其余promise对象大不同的感受,因此我想正确的数据结构应该是这样的。
经过
next
进行链式调用,每一个promise仅保存下一个所指向的promise,而且当前的Promise状态决定下一个Promise调用resolve
仍是reject
,再经过这些方法来决定当前promise的状态。今后无限套娃~ 同时这样你也不须要两个数组来对成功的方法与错误的方法进行分离存储,所有都是用next指向,这和Promise的概念也是相同的,Promise的状态仅会被一个改变状态函数所影响,其他的都将会忽略。
下面才是本篇文章正真的开始,根据以上总结出的经验,咱们来实现一个完整的并彻底符合Promise A+规范的Promise。
咱们先来总览一下MDN上描述的Promise方法:
静态方法:
Promise.all(iterable)
Promise.race(iterable)
Promise.reject(reason)
Promise.resolve(value)
实例方法:
Promise.prototype.catch(onReject)
Promise.prototype.then(onFulfilled,onRejected)
Promise.prototype.finally
具体细节就不赘述了,不太清楚的小伙伴请自行去mdn上进行学习后再回来看具体实现,下面咱们开始吧。
人狠话很少,先上代码再讲解
let MyPromise = (function () {
function resolve(res) {
// 若是存在状态则直接返回
if (this['[[PromiseStatus]]'] != 'pending') return
// 若是接收到的值是本身自己则报错
if (res === this) {
throw new Error(
'TypeError: Chaining cycle detected for promise #<Promise>')
}
// 若是res 是一个promise对象 则等待其值而后返回
this['[[PromiseStatus]]'] = 'fulfilled'
this['[[PromiseValue]]'] = res
// promise 是一个宏任务 使用 setTimeout 进行模拟
setTimeout(() => {
if (this.next) {
this.next()
delete this.next // 解除关联关系 防止没法被垃圾回收器回收
}
}, 0)
}
function reject(res) {
// 若是存在状态则直接返回
if (this['[[PromiseStatus]]'] != 'pending') return
this['[[PromiseStatus]]'] = 'rejected'
this['[[PromiseValue]]'] = res
setTimeout(() => {
// 若是有下一个promise则传值,若是没有则直接报错
if (this.next) {
this.next() // 将会建立下一个promise 在then方法中进行定义
delete this.next // 解除关联关系 防止没法被垃圾回收器回收
} else {
throw new Error(res)
}
}, 0)
}
return function (fn) {
this['[[PromiseStatus]]'] = 'pending' // 保存当前promise状态
this['[[PromiseValue]]'] = undefined // 保存当前promise的值
this.next = null // 建立下一个promise
// 保存全部的finally方法 当改promise当用完前运行内部全部方法
this.finallyArr = []
// 调用用户传入的函数,并将resolve与reject回传
fn(resolve.bind(this), reject.bind(this))
}
})()
复制代码
这里跟你们强调说明一下,使用setTimeout
不只仅是单纯为了模仿异步效果,而是这样将调用next
方法变为一个宏任务,能够确保在链式调用时,then
方法以后进行执行。
这里将当传入的参数为promise的处理和finally方法的处理暂时去除了,等下面涉及到时再和你们单独说明。
该方法是整个Promise的核心,而且Promise A+规范规定的也是该方法,下面咱们继续先上代码,我会把注释写全,再和你们讨论实现思路。
MyPromise.prototype.then = function (onFulfilled, onRejected) {
let _self = this // 记录前一个promise
let promise = new MyPromise(function (resolve, reject) {
// 将方法保存下来 在上一个的next中进行触发
_self.next = () => {
// 上一个promise的状态 决定调用哪一个函数方法
// 是成功的 则调用 onFulfilled
if (_self['[[PromiseStatus]]'] == 'fulfilled') {
// 若是onFulfilled不存在 则将上一个的值直接传递给当前全新的promise
if (typeof onFulfilled !== 'function') {
resolve.call(this, _self['[[PromiseValue]]'])
}
// 当前promise的状态由 执行的方法决定
try {
// 将上一个的值进行回传
let data = onFulfilled(_self['[[PromiseValue]]'])
resolve.call(this, data) // 成功 则调用 resolve方法
} catch (error) {
reject.call(this, error) // 失败则调用 reject
}
}
// 是失败的 则调用 onRejected
else if (_self['[[PromiseStatus]]'] == 'rejected') {
// 若是没有错误处理方法则直接报错 当前的值
if (typeof onRejected !== 'function') {
reject.call(this, _self['[[PromiseValue]]'])
}
// 当前promise的状态由 执行的方法决定
try {
let data = onRejected(_self['[[PromiseValue]]'])
resolve.call(this, data) // 成功 则调用 resolve方法
} catch (error) {
reject.call(this, error) // 失败则调用 reject
}
}
// 若是是等待状态 就空
}
})
// 返回一个全新的promise
return promise
}
}
复制代码
上面的代码充斥着高阶函数和call、apply,可能不太好理解,下面和你们一块儿探讨一下 首先思路和大错特错那一章节中是同样的,即:
当前Promise的执行resolve、reject是由上一个Promise决定的
当前Promise的状态,是由该Promise的resolve、reject决定的
咱们在新建的Promise中并未去触发改变该状态的函数,而是将其保存在了上一个Promise的next属性中,当上一个Promise触发resolve方法时再去触发,这样就完成了异步的状态改变。
下面拿一个示例说说整个Promise发生的流程:
new MyPromise(function (resolve) {
setTimeout(() => {
resolve(42)
}, 1000);
})
.then(res =>{
console.log(res)
})
复制代码
第一步:建立一个新的Promise
,将一个匿名方法传入,将会在构造函数中被调用,等待一秒后会去触发resolve
方法
...
fn(resolve.bind(this), reject.bind(this))
复制代码
第二步:调用首个Promise
的then方法,建立一个全新的等待状态的Promise2
,请将改变其状态的方法存在Promise1
的next
属性中
...
let promise = new MyPromise(function (resolve, reject) {
_self.next = () => {
...
}
})
return promise
复制代码
第三步:第一步的匿名函数setTimeout
触发resolve
方法,改变了首个Promise
的状态和值,同时会去检查是否存在下一个Promise,若是存在则执行
...
if (this.next) {
this.next()
delete this.next // 解除关联关系 防止没法被垃圾回收器回收
}
...
复制代码
第四步:next方法带着首个Promise
的状态来了,改变Promise2
的状态
...
// 上一个promise的状态 决定调用哪一个函数方法
// 是成功的 则调用 onFulfilled
if (_self['[[PromiseStatus]]'] == 'fulfilled') {
// 若是onFulfilled不存在 则将现有的值传递给下一个全新的promise
if (typeof onFulfilled !== 'function'){
resolve.call(this, _self['[[PromiseValue]]'])
}
// 当前promise的状态由 执行的方法决定
// 将上一个的值进行回传
try {
let data = onFulfilled(_self['[[PromiseValue]]'])
resolve.call(this, data) // 成功 则调用 resolve方法
} catch (error) {
reject.call(this, error) // 失败则调用 reject
}
}
...
复制代码
第五步: Promise2
的resolve
或reject
再次触发next
方法,以此往复
咱们再来看看这两句代码:
...
if (typeof onFulfilled !== 'function') {
resolve.call(this, _self['[[PromiseValue]]'])
}
...
if (typeof onRejected !== 'function') {
reject.call(this, _self['[[PromiseValue]]'])
}
...
复制代码
但凡遇到空的then
方法,将会直接将上一个Promise的状态和值复制,可以继续向下传递,就像这样子:
new MyPromise(function (resolve) {
resolve(42)
})
.then()
.then()
.then(res =>{
console.log(res) // 42
})
复制代码
对于空的Promise.then()
根本无需理会,一样返回一个全新的空Promise
便可
咱们再回过头将reslove
方法进行扩充,若是传入的值是Promise对象呢?咱们将等待其完成而后再进行赋值操做。
...
// 若是res 是一个promise对象 则等待其值而后返回
if (res instanceof MyPromise) {
res.then(val => {
this['[[PromiseStatus]]'] = 'fulfilled'
this['[[PromiseValue]]'] = val
}, err => {
this['[[PromiseStatus]]'] = 'rejected'
this['[[PromiseValue]]'] = err
})
}
else {
this['[[PromiseStatus]]'] = 'fulfilled'
this['[[PromiseValue]]'] = res
}
...
复制代码
then
方法这是整个Promise
实现最难的地方,你们要是没理解的话能够本身动手跑一下,我会将完整实现所有贴在最后。
实现了then
方法后,你会发现其实catch
方法只是then
方法的阉割版,即没有了成功的回调方法,只有失败的方法。实现代码很简单:
MyPromise.prototype.catch = function (onRejected) {
// 直接调用then方法 并返回then返回的 promise
return MyPromise.prototype.then.call(this, null, onRejected)
}
复制代码
没错,直接调then
方法便可
该方法定义了不管Promise
失败与否,都将会执行的函数。以前实现的then
、catch
方法都是和Promise
的状态与值挂钩的, 而finally
方法不是,只是单纯的在一个Promise
调用结束后触发的方法,甚至它连回调参数也没有。因此咱们从新设置一个对象参数来存储finally
的参数。
return function (fn) {
// 保存当前promise状态
this['[[PromiseStatus]]'] = 'pending'
// 保存当前promise的值
this['[[PromiseValue]]'] = undefined
// 指向下一个pomise
this.next = null
// 保存全部的finally方法 当改promise当用完前运行内部全部方法
=> this.finallyArr = []
// 调用用户传入的函数,并将resolve与reject回传
fn(resolve.bind(this), reject.bind(this))
}
复制代码
在finally
方法中进行添加
MyPromise.prototype.finally = function (onFinally) {
// 链式调用 可是不会返回新的promise对象
this.finallyArr.push(onFinally)
return this
}
复制代码
同时注意,finally
返回的是自身,与then、catch
是不一样的。 如今方法都存储起来了,只要在该Promise
执行后调用就能够了,resolve
函数添加代码以下:
...
setTimeout(() => {
// 遍历finishArr并链式执行
// 遍历执行finally 方法
while (this.finallyArr.length > 0) {
this.finallyArr.shift()()
}
delete this.finallyArr
if (this.next) {
this.next()
delete this.next // 解除关联关系 防止没法被垃圾回收器回收
}
}, 0)
...
复制代码
而且当所有执行后就把该属性删除,这样在浏览器中打印出来就和原生的如出一辙了,哈哈哈哈哈哈哈。
到此,Promise的实例方法所有完成,咱们来看看静态方法吧。
它返回一个成功状态的Promise
,虽然我感受它和我在闭包内实现的resolve
方法差很少,可是我没有想到一个很好的办法来进行整合,若是有小伙伴想到的话请第一时间告知我!~ 代码实现很简单。
MyPromise.resolve = function (value) {
// 若是是promise类型直接返回
if (value instanceof MyPromise) return value
return new MyPromise(function (resolve) {
resolve(value)
})
}
复制代码
它与MyPromise.resolve
是同样的道理。
MyPromise.reject = function (value) {
// 若是是promise类型直接返回
if (value instanceof MyPromise) return value
return new MyPromise(function (resolve, reject) {
reject(value)
})
}
复制代码
该方法的定义是但凡接收到的类数组参数中有一个参数成功了就直接返回包含该参数的Promise
,失败同理,直接上代码:
MyPromise.race = function (arr) {
let promise = new MyPromise(function (resolve, reject) {
for (let i = 0; i < arr.length; i++) {
// 若是是promise 则使用then 进行监听 谁先完成或者失败就直接改变状态
if (arr[i] instanceof MyPromise) {
arr[i].then(function (res) {
resolve(res)
}, function (err) {
reject(err)
})
} else {
// 若是不是promise 则直接返回结果
resolve(arr[i])
}
}
})
return promise
}
复制代码
在如今的Promise
实现下,去异步监听值得变化变的异常简单,从而可以判断谁是第一个完成或失败的,从而返回它的状态。
该方法与race相反,因此类数组中的参数成功了才会返回一个包含它们结果的Promise
,失败则直接返回错误消息。实现起来相较race稍难一点,须要判断当前类数组中的参数是否所有完成,可是在then
方法下都信手捏来。
MyPromise.all = function (arr) {
let promise = new MyPromise(function (resolve, reject) {
let result = [] // 将结果保存
let start = 0, // 开始异步的数量
finish = 0 // 完成异步的数量
for (let i = 0; i < arr.length; i++) {
// 若是是promise 则使用then 进行监听
if (arr[i] instanceof MyPromise) {
++start // 记录当前开始了多少个promise
// 使用then就会被挂起监听
arr[i].then(res => {
++finish // 记录当前完成了多少个promise
result[i] = res
// 所有完成则返回成功状态与数据
if (start == finish) resolve(result)
}, err => {
reject(err) // 错了就直接返回
})
} else {
result[i] = arr[i]
}
}
// 若是没有异步方法 则直接返回结果
if (!start) resolve(result)
})
return promise
}
复制代码
经过在then
方法中对start
、finish
的对比,从而可以知道当前完成的Promise
是不是最后一个,进而返回所有结果。
到这里就将整个Promise
实现啦,同时我我的也使用promises-aplus-tests
进行了测试,符合所有规范,你们能够安心食用。
let MyPromise = (function () {
function resolve(res) {
if (this['[[PromiseStatus]]'] != 'pending') return // 若是存在状态则直接返回
// 若是接收到的值是本身自己则报错
if (res === this) {
throw new Error('TypeError: Chaining cycle detected for promise #<Promise>')
}
// 若是res 是一个promise对象 则等待其值而后返回
if (res instanceof MyPromise) {
res.then(val => {
this['[[PromiseStatus]]'] = 'fulfilled'
this['[[PromiseValue]]'] = val
}, err => {
this['[[PromiseStatus]]'] = 'rejected'
this['[[PromiseValue]]'] = err
})
} else {
this['[[PromiseStatus]]'] = 'fulfilled'
this['[[PromiseValue]]'] = res
}
// promise 是一个宏任务 使用 setTimeout 进行模拟
setTimeout(() => {
// 遍历finishArr并链式执行
// 遍历执行finally 方法
while (this.finallyArr.length > 0) {
this.finallyArr.shift()()
}
delete this.finallyArr
if (this.next) {
this.next()
delete this.next // 解除关联关系 防止没法被垃圾回收器回收
}
}, 0)
}
function reject(res) {
if (this['[[PromiseStatus]]'] != 'pending') return // 若是存在状态则直接返回
this['[[PromiseStatus]]'] = 'rejected'
this['[[PromiseValue]]'] = res
setTimeout(() => {
// 遍历执行finally 方法
while (this.finallyArr.length > 0) {
this.finallyArr.shift()()
}
delete this.finallyArr
// 若是有下一个promise则传值,若是没有则直接报错
if (this.next) {
this.next()
delete this.next // 解除关联关系 防止没法被垃圾回收器回收
} else {
throw new Error(res)
}
}, 0)
}
return function (fn) {
this['[[PromiseStatus]]'] = 'pending'
this['[[PromiseValue]]'] = undefined
this.next = null
this.finallyArr = [] // 保存全部的finally方法 当改promise当用完前运行内部全部方法
fn(resolve.bind(this), reject.bind(this))
}
})()
MyPromise.resolve = function (value) {
// 若是是promise类型直接返回
if (value instanceof MyPromise) return value
return new MyPromise(function (resolve) {
resolve(value)
})
}
MyPromise.reject = function (value) {
// 若是是promise类型直接返回
if (value instanceof MyPromise) return value
return new MyPromise(function (resolve, reject) {
reject(value)
})
}
MyPromise.all = function (arr) {
let promise = new MyPromise(function (resolve, reject) {
let result = [] // 将结果保存
let start = 0, // 开始异步数量
finish = 0 // 完成异步的数量
for (let i = 0; i < arr.length; i++) {
// 若是是promise 则使用then 进行监听
if (arr[i] instanceof MyPromise) {
++start // 记录当前开始了多少个promise
// 使用then就会被挂起监听
arr[i].then(res => {
++finish // 记录当前完成了多少个promise
result[i] = res
if (start == finish) resolve(result) // 所有完成则返回成功状态与数据
}, err => {
reject(err) // 错了就直接返回
})
} else {
result[i] = arr[i]
}
}
// 若是没有异步方法 则直接返回结果
if (!start) resolve(result)
})
return promise
}
MyPromise.race = function (arr) {
let promise = new MyPromise(function (resolve, reject) {
for (let i = 0; i < arr.length; i++) {
// 若是是promise 则使用then 进行监听 谁先完成或者失败就直接改变状态
if (arr[i] instanceof MyPromise) {
arr[i].then(function (res) {
resolve(res)
}, function (err) {
reject(err)
})
} else {
// 若是不是promise 则直接返回结果
resolve(arr[i])
}
}
})
return promise
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
let _self = this // 记录前一个promise
let promise = new MyPromise(function (resolve, reject) {
// 将方法保存下来 在上一个的next中进行改变状态操做
_self.next = () => {
// 上一个promise的状态 决定调用哪一个函数方法
// 当前是成功的 则调用 onFulfilled
if (_self['[[PromiseStatus]]'] == 'fulfilled') {
// 若是onFulfilled不存在 则将现有的值传递给下一个全新的promise
if (typeof onFulfilled !== 'function') {
resolve.call(this, _self['[[PromiseValue]]'])
}
// 当前promise的状态由 执行的方法决定
try {
let data = onFulfilled(_self['[[PromiseValue]]'])
resolve.call(this, data) // 成功 则调用 resolve方法
} catch (error) {
reject.call(this, error) // 失败则调用 reject
}
}
// 当前是失败的 则调用 onRejected
else if (_self['[[PromiseStatus]]'] == 'rejected') {
// 若是没有错误处理方法则直接报错 当前的值
if (typeof onRejected !== 'function') {
reject.call(this, _self['[[PromiseValue]]'])
}
// 当前promise的状态由 执行的方法决定
try {
let data = onRejected(_self['[[PromiseValue]]'])
resolve.call(this, data) // 成功 则调用 resolve方法
} catch (error) {
reject.call(this, error) // 失败则调用 reject
}
}
// 若是是等待状态 就空
}
})
// 须要返回一个全新的promise 而且这个promise就是当前处理的这个
return promise
}
MyPromise.prototype.catch = function (onRejected) {
// 直接调用then方法 并返回then返回的 promise
return MyPromise.prototype.then.call(this, null, onRejected)
}
MyPromise.prototype.finally = function (onFinally) {
// 链式调用 可是不会返回新的promise对象
this.finallyArr.push(onFinally)
return this
}
Promise.deferred = Promise.defer = function () {
var dfd = {}
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
module.exports = Promise
复制代码
Promise.deferred
是给测试提供的接口,无视。
我还记得那是一个晴朗的早晨,外面天气很好,我看到一个题目姚手撸一个Promise
,我说这有什么难的,我来。 未曾想,实现加上写文章整整花费了一个礼拜的业余时间,着实有点难顶。在此厚脸皮的跟你们要个赞,你当作吗?
我作完之后去网上查阅了一下,你们好像都用数组对回调方法进行存储,若是我一开始也去看这一类的文章再本身动手,可能脑海里也会习惯性的用已知方法解决。其实我想说就是,解决问题有时候没必要一味的去模仿、照搬,静下来本身想想,也许你会有你本身的答案。