Abstract

Promise的意思是承诺(在红宝书中翻译为期约),新华字典:(动)对某项事务答应照办。

Promise最早出现在Commn JS,随后形成了Promise/A规范。

Promise是异步编程的一种解决方案,简单讲是一个容器其中保存这某个未来才会结束的事件的结果,从语法上说,Promise对象可以获取异步操作的消息,而且Promise提供了统一的API对于各种异步操作都可以用同样的方法进行处理

比如我们发出请求调用服务器数据,由于网络延时原因,我们此时无法调用到数据,我们可以接着执行其它任务,等到将来某个时间节点服务器响应数据到达客户端,我们即可使用promise自带的一个回调函数来处理数据,所以要想真正理解Promise我们必须从回调开始

1、回调函数定义

回调是一个在另一个函数完成执行后所执行的函数——故此得名“回调”。

2、为什么需要回调

JavaScript 是一种事件驱动的单线程语言。这意味着,在继续之前, JavaScript 不会等待响应,而是继续执行且同时监听事件。

举例:

function first(){
console.log(1);
}
function second(){
console.log(2);
}
first();
second();
//1
//2

如果再first中有计时器呢?

function first(){
// 模拟代码延迟
setTimeout( function(){
console.log(1);
}, 500 );
}
function second(){
console.log(2);
}
first();
second();
//2
//1
//并不是 JavaScript 没有按照我们想要的顺序执行我们的函数,而是在继续执行 second() 之前, JavaScript 没有等待 first() 的响应。

1.回调函数字面意思:就是回调就是一个函数的调用过程。那么就从理解这个调用过程开始吧。函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b。那么这个过程就叫回调。

2.回调函数的意义:

异步:一般ajax请求都是异步的。请求发出去后,处理器会继续执行下面的代码。如果你想ajax请求完成后,做一些事情,显然,直接在下一行写代码是达不到目的。而作为回调函数传给ajax请求,可以控制请求在哪个阶段去调用回调函数,并且不用担心后面的代码执行到什么地方了。

3.回调函数的执行:就是异步的函数体执行成功或失败调用的传递进来的函数,调用的函数就是回调,为了不影响代码执行的效率,我们不会等待异步的代码执行,而是直接像下面执行,但是像请求,计时器,事件等操作我们在一些情况下必须拿到对应的数据或者返回值,这个时候就可以在异步函数里传入一个回调函数,也就是在异步操作执行结束之后会调用这个回调函数执行一段代码

3.回调的局限性

//普通函数
// 第一步,打开冰箱
function open(){
setTimeout(()=>{
console.log('打开冰箱');
return 'success';
}, 1000)
} // 第二步,放牛进去
function settle(){
setTimeout(()=>{
console.log('放牛进去');
return 'success';
}, 3000)
} // 第三步,关上冰箱
function close(){
setTimeout(()=>{
console.log('关上冰箱');
return 'success';
}, 1000)
} function closeCow(){
open();
settle();
close()
} closeCow(); //"打开冰箱"
//"关上冰箱"?
//"放牛进去"? //回调函数实现
function closeCow() {
setTimeout(() => {
console.log("打开冰箱");
setTimeout(() => {
console.log("放牛进去");
setTimeout(() => {
console.log("关闭冰箱");
}, 1000);
}, 3000);
}, 1000);
}

如何解决回调嵌套?

1.保持你的代码简短(给函数取有意义的名字,见名知意,而非匿名函数,写成一大坨)

2.模块化(函数封装,打包,每个功能独立,可以单独的定义一个js文件Vue,react中通过import导入就是一种体现)

3.Promise/生成器/ES6等

4.Promise的特点

特点1

Promise有三种状态,分别是pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个操作,Promise(承诺)这个名字也是由此而来,表示其他手段无法改变状态

特点2

如果状态发生了改变,就不会再改变而且任何时候都可以得到这个结果,Promise状态的改变只有两种情况一种是变为fulfilled另一种是变为rejected,改变后状态就凝固了不会再有任何改变,会一直保持这个结果,这是就成为resolved(已定形)。而且,如果改变已经发生你也可以对Promise添加回调函数获得结果,这与事件有根本的区别,事件如果不监听(dom.addEventListener),错过之后就无法再得到结果

特点3

无法取消Promise一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

5.Promise的使用

基础语法

const promise = new Promise((resolve, reject) => {
resolve('fulfilled...'); // 状态由 pending --> fulfilled
}); promise.then(res => {
console.log(res); // 只会调用 resolve
}, err => {
console.log(err); // 不会调用 rejected
})
// fulfilled

Promise

1.特性:

​ 立即执行,自身是异步

let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
}); promise.then(function() {
console.log('resolved.');
}); console.log('Hi!');
// ?
// ?
// ?
上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。

2.特性

​ 值穿透

Promise.resolve(1)
.then(2)
.then(Promise.resolve(3))
.then(console.log) // 输出 ?
//Promise的then方法的参数期望是函数,传入非函数则会发生值穿透。

6.Promise API

比较简单,

建议查看MDN文档

7.手写Promise

核心点

1.状态的改变

2.值的改变

3.返回值

4.class的使用

基础版

// 构建
const PENDING = 'pending'//进行中
const FULFILLED = 'fulfilled'//已成功
const REJECTED = 'rejected'//已失败 class NewPromise {
//接受一个函数handle
constructor (handle) {
if (!isFunction(handle)) {
throw new Error('MyPromise must accept a function as a parameter')
}
// 添加状态
this._status = PENDING
// 添加状态
this._value = undefined
// 添加成功回调函数队列
this._fulfilledQueues = []
// 添加失败回调函数队列
this._rejectedQueues = []
// 执行handle
try {
//执行回调函数,class是严格模式指向undefined,通过bind修改指向resove的指向
handle(this._resolve.bind(this), this._reject.bind(this))
//收集错误
} catch (err) {
this._reject(err)
}
}
} //then方法的对应状态的回调执行时机,值的改变
then (onFulfilled, onRejected) {
const { _value, _status } = this
switch (_status) {
// 当状态为pending时,将then方法回调函数加入执行队列等待执行
case PENDING:
this._fulfilledQueues.push(onFulfilled)
this._rejectedQueues.push(onRejected)
break
// 当状态已经改变时,立即执行对应的回调函数
case FULFILLED:
onFulfilled(_value)
break
case REJECTED:
onRejected(_value)
break
}
// 返回一个新的Promise对象
return new MyPromise((onFulfilledNext, onRejectedNext) => {
})
} //那返回的新的 Promise 对象什么时候改变状态?改变为哪种状态呢?
//then方法确认Promise状态
then (onFulfilled, onRejected) {
const { _value, _status } = this
// 返回一个新的Promise对象
return new MyPromise((onFulfilledNext, onRejectedNext) => { // 封装一个成功时执行的函数
let fulfilled = value => {
try {
if (!isFunction(onFulfilled)) {
onFulfilledNext(value)
} else {
let res = onFulfilled(value);
if (res instanceof MyPromise) {
// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
res.then(onFulfilledNext, onRejectedNext)
} else {
//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
onFulfilledNext(res)
}
}
} catch (err) {
// 如果函数执行出错,新的Promise对象的状态为失败
onRejectedNext(err)
}
} // 封装一个失败时执行的函数
let rejected = error => {
try {
if (!isFunction(onRejected)) {
onRejectedNext(error)
} else {
let res = onRejected(error);
if (res instanceof MyPromise) {
// 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调
res.then(onFulfilledNext, onRejectedNext)
} else {
//否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数
onFulfilledNext(res)
}
}
} catch (err) {
// 如果函数执行出错,新的Promise对象的状态为失败
onRejectedNext(err)
}
} // 执行对应函数
switch (_status) {
// 当状态为pending时,将then方法回调函数加入执行队列等待执行
case PENDING:
this._fulfilledQueues.push(fulfilled)
this._rejectedQueues.push(rejected)
break
// 当状态已经改变时,立即执行对应的回调函数
case FULFILLED:
fulfilled(_value)
break
case REJECTED:
rejected(_value)
break
}
})
}

完全版--1

ES6语法实现Promise  // 判断变量否为function  const isFunction = variable => typeof variable === 'function'  // 定义Promise的三种状态常量  const PENDING = 'PENDING'  const FULFILLED = 'FULFILLED'  const REJECTED = 'REJECTED'  class MyPromise {    constructor (handle) {      if (!isFunction(handle)) {        throw new Error('MyPromise must accept a function as a parameter')      }      // 添加状态      this._status = PENDING      // 添加状态      this._value = undefined      // 添加成功回调函数队列      this._fulfilledQueues = []      // 添加失败回调函数队列      this._rejectedQueues = []      // 执行handle      try {          //class是严格模式,如果不bind会Uncaught TypeError: Cannot read property  undefined        handle(this._resolve.bind(this), this._reject.bind(this))       } catch (err) {        this._reject(err)      }    }    // 添加resovle时执行的函数    _resolve (val) {      const run = () => {          //不是进行状态,已凝固直接返回        if (this._status !== PENDING) return        // 依次执行成功队列中的函数,并清空队列        const runFulfilled = (value) => {          let cb;          while (cb = this._fulfilledQueues.shift()) {            cb(value)          }        }        // 依次执行失败队列中的函数,并清空队列        const runRejected = (error) => {          let cb;          while (cb = this._rejectedQueues.shift()) {            cb(error)          }        }        /* 如果resolve的参数为Promise对象,则必须等待该Promise对象状态改变后,          当前Promsie的状态才会改变,且状态取决于参数Promsie对象的状态        */        if (val instanceof MyPromise) {          val.then(value => {            this._value = value            this._status = FULFILLED            runFulfilled(value)          }, err => {            this._value = err            this._status = REJECTED            runRejected(err)          })        } else {          this._value = val          this._status = FULFILLED          runFulfilled(val)        }      }      // 为了支持同步的Promise,这里采用异步调用      setTimeout(run, 0)    }    // 添加reject时执行的函数    _reject (err) {       if (this._status !== PENDING) return      // 依次执行失败队列中的函数,并清空队列      const run = () => {        this._status = REJECTED        this._value = err        let cb;          //将删除的第一个元素的值赋值给cb        while (cb = this._rejectedQueues.shift()) {          cb(err)        }      }      // 为了支持同步的Promise,这里采用异步调用      setTimeout(run, 0)    }    // 添加then方法    then (onFulfilled, onRejected) {      const { _value, _status } = this      // 返回一个新的Promise对象      return new MyPromise((onFulfilledNext, onRejectedNext) => {        // 封装一个成功时执行的函数        let fulfilled = value => {          try {            if (!isFunction(onFulfilled)) {              onFulfilledNext(value)            } else {              let res =  onFulfilled(value);              if (res instanceof MyPromise) {                // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调                res.then(onFulfilledNext, onRejectedNext)              } else {                //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数                onFulfilledNext(res)              }            }          } catch (err) {            // 如果函数执行出错,新的Promise对象的状态为失败            onRejectedNext(err)          }        }        // 封装一个失败时执行的函数        let rejected = error => {          try {            if (!isFunction(onRejected)) {              onRejectedNext(error)            } else {                let res = onRejected(error);                if (res instanceof MyPromise) {                  // 如果当前回调函数返回MyPromise对象,必须等待其状态改变后在执行下一个回调                  res.then(onFulfilledNext, onRejectedNext)                } else {                  //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数                  onFulfilledNext(res)                }            }          } catch (err) {            // 如果函数执行出错,新的Promise对象的状态为失败            onRejectedNext(err)          }        }        switch (_status) {          // 当状态为pending时,将then方法回调函数加入执行队列等待执行          case PENDING:            this._fulfilledQueues.push(fulfilled)            this._rejectedQueues.push(rejected)            break          // 当状态已经改变时,立即执行对应的回调函数          case FULFILLED:            fulfilled(_value)            break          case REJECTED:            rejected(_value)            break        }      })    }    // 添加catch方法    catch (onRejected) {      return this.then(undefined, onRejected)    }    // 添加静态resolve方法    static resolve (value) {      // 如果参数是MyPromise实例,直接返回这个实例      if (value instanceof MyPromise) return value      return new MyPromise(resolve => resolve(value))    }    // 添加静态reject方法    static reject (value) {      return new MyPromise((resolve ,reject) => reject(value))    }    // 添加静态all方法    static all (list) {      return new MyPromise((resolve, reject) => {        /**         * 返回值的集合         */        let values = []        let count = 0        for (let [i, p] of list.entries()) {          // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve          this.resolve(p).then(res => {            values[i] = res            count++            // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled            if (count === list.length) resolve(values)          }, err => {            // 有一个被rejected时返回的MyPromise状态就变成rejected            reject(err)          })        }      })    }    // 添加静态race方法    static race (list) {      return new MyPromise((resolve, reject) => {        for (let p of list) {          // 只要有一个实例率先改变状态,新的MyPromise的状态就跟着改变          this.resolve(p).then(res => {            resolve(res)          }, err => {            reject(err)          })        }      })    }    finally (cb) {      return this.then(        value  => MyPromise.resolve(cb()).then(() => value),        reason => MyPromise.resolve(cb()).then(() => { throw reason })      );    }  }

注释:

1.Try

2.consturctor

完全版-2

ES5语法实现(function () {    // 判断function    function isFunction(fn) {        return typeof fn === 'function';    }    // 状态 pending、fulfilled、rejected    var PENDING = 'pending';    var FULFILLED = 'fulfilled';    var REJECTED = 'rejected';    // 构造方法    var Kromise = function (handle) {        // 当前状态        this._status = PENDING;        // 添加成功回调队列        this._fulfilledQueue = [];        // 添加失败回调队列        this._rejectedQueue = [];        // 引用当前this对象        var self = this;        if (!isFunction(handle)) {            throw new Error('Parameter handle is not a function!')        }        // 添加resolve时执行的函数        function _resolve(val) {            var run = function () {                if (self._status !== PENDING) return;                // 依次执行成功队列中的函数,并清空队列                var runFulfilled = function (res) {                    var resolve;                    while (resolve = self._fulfilledQueue.shift()) { // 出栈                        resolve(res);                    }                };                // 依次执行失败队列中的函数,并清空队列                var runRejected = function (err) {                    var reject;                    while (reject = self._rejectedQueue.shift()) { // 出栈                        reject(err);                    }                };                /* 如果resolve的参数为Kromise对象,则必须等待该Kromise对象状态改变后,                 * 当前Kromise的状态才会改变,且状态取决于参数Kromise对象的状态                 */                if (val instanceof Kromise) {                    val.then(function (value) {                        self._status = FULFILLED;                        self._value = value;                        runFulfilled(value)                    }, function (err) {                        self._status = REJECTED;                        self._value = err;                        runRejected(err);                    })                } else {                    self._status = FULFILLED;                    self._value = val;                    runFulfilled(val);                }            };            // 为了支持同步的Promise,这里采用异步调用            setTimeout(run, 0)        }        // 添加reject时执行的函数        function _reject(err) {            var run = function () {                if (self._status !== PENDING) return;                // 依次执行成功队列中的函数,并清空队列                self._status = REJECTED;                self._value = err;                var reject;                while (reject = self._fulfilledQueue.shift()) { // 出栈                    reject(err);                }            };            // 为了支持同步的Promise,这里采用异步调用            setTimeout(run, 0)        }        // 执行handle,捕获异常        try {            handle(_resolve.bind(this), _reject.bind(this));        } catch (e) {            _reject(e);        }    };    // 属性    Kromise.length = 1;    // 实例方法    // 实现then方法    Kromise.prototype.then = function (onFulfilled, onRejected) {        var self = this;        // 返回一个新的Kromise对象        return new Kromise(function (onFulfilledNext, onRejectedNext) {            // 成功时的回调            var fulfilled = function (val) {                try {                    // 如果不是函数,值穿透                    if (!isFunction(onFulfilled)) {                        onFulfilledNext(val)                    } else {                        var res = onFulfilled(val);                        // 如果当前回调函数返回Kromise对象,必须等待其状态改变后在执行下一个回调                        if (res instanceof Kromise) {                            res.then(onFulfilledNext, onRejectedNext);                        } else {                            //否则会将返回结果直接作为参数,传入下一个then的回调函数,并立即执行下一个then的回调函数                            onFulfilledNext(res);                        }                    }                } catch (e) {                    // 如果函数执行出错,新的Kromise对象的状态为失败                    onRejectedNext(e);                }            };            // 失败时的回调            var rejected = function (err) {                try {                    if (!isFunction(onRejected)) {                        onRejectedNext(err)                    } else {                        var res = onRejected(err);                        if (res instanceof Kromise) {                            res.then(onFulfilledNext, onRejectedNext);                        } else {                            onFulfilledNext(res);                        }                    }                } catch (e) {                    onRejectedNext(e)                }            };            switch (self._status) {                // 当状态为pending时,将then方法回调函数加入执行队列等待执行                case PENDING:                    self._fulfilledQueue.push(fulfilled);                    self._rejectedQueue.push(rejected);                    break;                // 当状态已经改变时,立即执行对应的回调函数                case FULFILLED:                    fulfilled(self._value);                    break;                case REJECTED:                    rejected(self._value);                    break;            }        });    };    // 实现catch方法    Kromise.prototype.catch = function (onRejected) {        return this.then(undefined, onRejected);    };    // 实现finally方法    Kromise.prototype.finally = function (onFinally) {        return this.then(function (value) {            Kromise.resolve(onFinally()).then(function () {                return value;            })        }, function (err) {            Kromise.resolve(onFinally()).then(function () {                throw new Error(err);            })        })    };    // 静态方法    // 实现resolve方法    Kromise.resolve = function (value) {        // 如果参数是Kromise实例,直接返回这个实例        if (value instanceof Kromise) {            return value;        }        return new Kromise(function (resolve) {            resolve(value)        })    };    // 实现reject方法    Kromise.reject = function (value) {        return new Kromise(function (resolve, reject) {            reject(value)        })    };    // 实现all方法    Kromise.all = function (arr) {        var self = this;        return new Kromise(function (resolve, reject) {            var values = [];            for (var i = 0, len = arr.length; i < len; i++) {                // 数组参数如果不是Kromise实例,先调用Kromise.resolve                self.resolve(arr[i]).then(function (res) {                    values.push(res);                    // 所有状态都变成fulfilled时返回的Kromise状态就变成fulfilled                    if (values.length === arr.length) {                        resolve(values);                    }                }, function (e) {                    // 有一个被rejected时返回的Kromise状态就变成rejected                    reject(e);                })            }        })    };    // 实现race方法    Kromise.race = function (arr) {        var self = this;        return new Kromise(function (resolve, reject) {            for (var i = 0, len = arr.length; i < len; i++) {                // 只要有一个实例率先改变状态,新的Kromise的状态就跟着改变                self.resolve(arr[i]).then(function (res) {                    resolve(res);                }, function (err) {                    reject(err);                })            }        })    };    // 实现any方法    Kromise.any = function (arr) {        var self = this;        return new Kromise(function (resolve, reject) {            var count = 0;            var errors = [];            for (var i = 0, len = arr.length; i < len; i++) {                // 只要有一个实例状态变为fulfilled,新的Kromise状态就会改变为fulfilled                self.resolve(arr[i]).then(function (res) {                    resolve(res);                }, function (err) {                    errors[count] = err;                    count++;                    // 否则等待所有的rejected,新的Kromise状态才会改变为rejected                    if (count === arr.length) {                        reject(errors);                    }                })            }        })    };    // 实现allSettled方法    Kromise.allSettled = function (arr) {        var results = [];        var len = arr.length;        for (var i = 0; i < len; i++) {            this.resolve(arr[i]).then(function (res) {                results.push({status: FULFILLED, value: res});            }, function (err) {                results.push({status: REJECTED, value: err});            })        }        // 一旦结束,状态总是`fulfilled`,不会变成`rejected`        return new Kromise(function (resolve, reject) {            resolve(results)        })    };    // 实现try方法    Kromise.try = function (fn) {        if (!isFunction(fn)) return;        return new Kromise(function (resolve, reject) {            return resolve(fn());        })    };    // 挂载    window.Kromise = Kromise;})();

总结

promise通过自己的回调嵌套解决别人的问题

8.参考文档

[1].JavaScript | MDN

[2].Promise迷你书

[3].廖雪峰的官方网站

[4].ES6网道教程

深入浅出Promise的更多相关文章

  1. 深入浅出:promise的各种用法

    https://mp.weixin.qq.com/s?__biz=MzAwNTAzMjcxNg==&mid=2651425195&idx=1&sn=eed6bea35323c7 ...

  2. ES6深入浅出-9 Promise-3.Promise的细节

    await 拿到用户信息,函数前面加await await等待Promise成功或者失败. 如果Promise里面失败了 什么也拿不到.报了一个错误,叫做不认识. 如果想拿到正常错误,就绪try一下 ...

  3. ES6深入浅出-9 Promise-2.Promise的用法

    回调是不需要return 就可以传递数据.缺点就是嵌套多了就成了回调地狱 回调的另外一个问题拿不准应该怎么去传这个参数.以为node.js为例.nodejs有个readFile去读取文件,读取成功就用 ...

  4. 深入浅出写一个多级异步回调从基础到Promise实现的Demo

    今天一时兴起,写了一个渐进升级的异步调用demo,记录一下. 1. 最基础的同步调用 //需求:f2在f1之后执行,且依赖f1的返回值.如下: function f1(){ var s="1 ...

  5. 深入理解jQuery、Angular、node中的Promise

    最初遇到Promise是在jQuery中,在jQuery1.5版本中引入了Deferred Object,这个异步队列模块用于实现异步任务和回调函数的解耦.为ajax模块.队列模块.ready事件提供 ...

  6. 深入浅出node(1) Node简介

    这一系列主要是自己在学习深入浅出node.js这本书的学习笔试,部分加入了自己的一些理解 分享给一起学习node的小伙伴 自己还是个初学者 有很多地方理解的不到位 一起交流 一 什么是node 1.1 ...

  7. 深入浅出 React Native:使用 JavaScript 构建原生应用

    深入浅出 React Native:使用 JavaScript 构建原生应用 链接:https://zhuanlan.zhihu.com/p/19996445 原文:Introducing React ...

  8. 深入浅出ES6(十七):展望未来

    作者 Jason Orendorff  github主页  https://github.com/jorendorff 出于对文章长度的考虑,我们还保留了一些尚未提及的新特性,在最后的这篇文章中我会集 ...

  9. 深入浅出ES6(十一):生成器 Generators,续篇

    作者 Jason Orendorff  github主页  https://github.com/jorendorff 欢迎回到深入浅出ES6专栏,望你在ES6探索之旅中收获知识与快乐!程序员们在工作 ...

随机推荐

  1. ip协议是哪一层的协议

    IP协议对应于OSI标准模型的网络层. TCP/IP: 数据链路层:ARP,RARP 网络层: IP,ICMP,IGMP 传输层:TCP ,UDP,UGP 应用层:Telnet,FTP,SMTP,SN ...

  2. CVE-2010-3974:Windows 传真封面编辑器 FxsCover.exe 双重释放漏洞调试分析

    0x01 堆空间申请后的双重释放 Windows FxsCover 程序存储封面编辑器的信息,封面编辑器是传真服务的一个组件,通过解析特定的传真封面文件(.cov)时,会调用类析构函数对同一内存中的栈 ...

  3. 使用jenkins一键打包发布vue项目

    jenkins的安装 Jenkins是一款开源 CI&CD 软件,用于自动化各种任务,包括构建.测试和部署软件. Jenkins 支持各种运行方式,可通过系统包.Docker 或者通过一个独立 ...

  4. yum makecache: error: argument timer: invalid choice: ‘fast’ (choose from ‘timer’)

    这是因为版本问题,centos8没有该参数,解决办法为:去掉fast参数,就可以了 sudo yum makecache

  5. 基于RRCF(robust random cut forest)的时间序列异常检测流程

    摘要:RRCF是亚马逊提出的一个流式异常检测算法,是对孤立森林的改进,可对时序或非时序数据进行异常检测.本文是我从事AIOps研发工作时所做的基于RRCF的时序异常检测方案. 1.      数据格式 ...

  6. 数据人必读!玩转数据可视化用这个就够了——高德LOCA API 2.0升级来袭!

    引言 "一图胜千言",大数据时代来临,数据与人们生活密切相关.复杂难懂且体量庞大的数据给人的感觉总是冷冰冰的,让人难以获取到重点信息,也找不出规律和特征,数据价值发挥不出来.空间数 ...

  7. Jmeter软件安装之Mac

    Jmeter软件安装之Mac 一.环境准备 安装JDK 下载Jmeter 二.下载Jmeter 下载地址: http://jmeter.apache.org/download_jmeter.cgi,下 ...

  8. 游戏中的2D OBB碰撞模型的碰撞算法介绍和实践

    前言 上一篇博文说道,射线与场景中模型上的所有三角形求交时,会大幅度影响效率且花费比较多的时间,因此会采取使用包围盒的形式,进行一个加速求交.在此文中介绍OBB碰撞模型的碰撞算法 OBB的碰撞模型 有 ...

  9. HEVC学习(一) —— HM的使用

    http://blog.csdn.net/hevc_cjl/article/details/8169182 首先自然是先把这个测试模型下载下来,链接地址如下:https://hevc.hhi.frau ...

  10. stm32开发笔记(三):stm32系列的GPIO基本功能之输出驱动LED灯、输入按键KEY以及Demo

    前言   stm32系列是最常用的单片机之一,不同的版本对应除了引脚.外设.频率.容量等'不同之外,其开发的方法是一样的.  本章讲解使用GPIO引脚功能驱动LED灯和接收Key按钮输入.   STM ...