前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【ES6基础】生成器(Generator)

【ES6基础】生成器(Generator)

原创
作者头像
前端达人
修改于 2019-06-29 16:08:59
修改于 2019-06-29 16:08:59
1.4K00
代码可运行
举报
文章被收录于专栏:前端达人前端达人
运行总次数:0
代码可运行

在这篇文章里《【ES6基础】迭代器(iterator)》,笔者介绍了迭代器及相关实例,我们要实现一个迭代器要写不少的代码。幸运的是,ES6引入了一个新的函数类型——生成器函数(Generator function),让我们能够更轻松更便捷的实现迭代器的相关功能。

今天笔者将从以下几个方面进行介绍生成器(Generator):

  • 什么是生成器
  • 生成器的基本语法
  • yield关键字
  • 生成器函数的类型检测
  • yield*委托
  • return(value)方法
  • throw(exception)方法
  • 向生成器传递数据
  • 生成器示例应用

本篇文章阅读时间预计15分钟

什么是生成器?

生成器第一次出现在CLU语言中。CLU语言是美国麻省理工大学的Barbara Liskov教授和她的学生们在1974年至1975年间所设计和开发出来的。Python、C#和Ruby等语言都受到其影响,实现了生成器的特性,生成器在CLU和C#语言中被称为迭代器(iterator),Ruby语言中称为枚举器(Enumerator)。

生成器的主要功能是:通过一段程序,持续迭代或枚举出符合某个公式或算法的有序数列中的元素。这个程序便是用于实现这个公司或算法的,而不需要将目标数列完整写出。

在ES6定义的生成器函数有别于普通的函数,生成器可以在执行当中暂停自身,可以立即恢复执行也可以过一段时间之后恢复执行。最大的区别就是它并不像普通函数那样保证运行到完毕。还有一点就是,在执行当中每次暂停或恢复循环都提供了一个双向信息传递的机会,生成器可以返回一个值,恢复它的控制代码也可以返回一个值。

生成器的基本语法

与普通函数语法的差别,在function关键字和函数名直接有个*号,这个*作为生成器函数的主要标识符,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *it(){}

*号的位置没有严格规定,只要在中间就行,你可以这么写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *it(){ }
function* it(){ }
function * it(){ }
function*it(){ }

笔者觉得*靠近函数名——function *it(){ },看着更为清晰,选择哪种书写方式完全凭个人喜好。

调用生成器也十分简单,就和调用普通函数一样,比如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
it();

同时也可以向生成器函数传递参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *it(x,y){ 

}
it(5,10);

yield关键字

生成器函数中,有一个特殊的新关键字:yield——用来标注暂停点,如下段代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function* generator_function(){ 
  yield 1; 
  yield 2; 
  yield 3;
}

如何运行生成器呢?如下段代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let generator = generator_function();
console.log(generator.next().value);//1
console.log(generator.next().value);//2
console.log(generator.next().value);//3
console.log(generator.next().done);//true

generator = generator_function();
let iterable = generator[Symbol.iterator]();
console.log(iterable.next().value);//1
console.log(iterable.next().value);//2
console.log(iterable.next().value);//3
console.log(iterable.next().done);//true

从上述代码我们可以看出:我们可以在实例化的生成器generator的对象里直接调用next()方法,同时我们也可以调用生成器原型链的Symbol.iterator属性方法调用next(),效果是一致的。我们每调用一次next()方法,就是顺序在对应的yield关键词的位置暂停,遵守迭代器协议,返回例如这样形式的对象: {value:"1",done:false},直到所有的yield的值消费完为止,再一次调用next()方法返回 {value:undefined,done:true},说明生成器的所有值已消费完。由此可见done属性用来标识生成器序列是否消费完了。当done属性为true时,我们就应该停止调用生成器实例的next方法。还有一点需要说明带有yield的生成器都会以惰性求值的顺序执行,当我们需要时,对应的值才会被计算出来。

生成器函数的类型检测

如何检测一个函数是生成器函数和生成器实例的原型呢,我们可以使用constructor.prototype属性检测,实例代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *genFn() {}
const gen=genFn();
console.log(genFn.constructor.prototype);//GeneratorFunction {}
console.log(gen.constructor.prototype);//Object [Generator] {}
console.log(gen instanceof genFn)//true
//判断某个对象是否为指定生成函数所对应的实例

除了以上方法进行判断,我们还可以使用@@tostringTag属性,如下段代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *genFn() {}
const gen=genFn();
console.log(genFn[Symbol.toStringTag]);//GeneratorFunction
console.log(gen[Symbol.toStringTag]);//Generator

yield*委托

yield* 可以将可迭代的对象iterable放在一个生成器里,生成器函数运行到yield * 位置时,将控制权委托给这个迭代器,直到耗尽为止,如下段代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function* generator_function_1(){ 
 yield 2; 
 yield 3;
}
function* generator_function_2(){
 yield 1; 
 yield* generator_function_1(); 
 yield* [4, 5];
}
const generator = generator_function_2();
console.log(generator.next().value); //1
console.log(generator.next().value); //2
console.log(generator.next().value); //3
console.log(generator.next().value); //4
console.log(generator.next().value); //4
console.log(generator.next().done);  //true

从上述代码中,我们在一个生成器中嵌套了一个生成器和一个数组,当程序运行至生成器generator_function_1()时,将其中的值消费完跳出后,再去迭代消费数组,消费完后,done的属性值返回true。

return(value)方法

你可以在生成器里使用return(value)方法,随时终止生成器,如下段代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function* generator_function(){ 
 yield 1; 
 yield 2; 
 yield 3;
}
const generator = generator_function();
console.log(generator.next().value); //1
console.log(generator.return(22).value); //22
console.log(generator.next().done);//true

从上述代码我们看出,使用return()方法我们提前终止了生成器,返回return里的值,再次调用next()方法时,done属性的值为true,由此可见return提前终止了生成器,其他的值也不再返回。

throw(exception)方法

除了用return(value)方法可以终止生成器迭代,我们还可以调用 throw(exception) 进行提前终止,示例代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *generator_function(){ 
    yield 1;
    yield 2;
    yield 3;    
}
const generator = generator_function();
console.log(generator.next());
try{
    generator.throw("wow");
}
catch(err){
    console.log(err);
}
finally{
    console.log("clean")
}
console.log(generator.next());

上段代码输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{ value: 1, done: false }
wow
clean
{ value: undefined, done: true }

由此可以看出,在生成器外部调用try...catch...finally,throw()异常被try...catch捕捉并返回,并执行了finally代码块中的代码,再次调用next方法,done属性返回true,说明生成器已被终止,提前消费完毕。

我们不仅可以在next执行过程中插入throw()语句,我们还可以在生成器内部插入try...catch进行错误处理,代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *generator_function(){ 
try { 
 yield 1; 
} catch(e) { 
 console.log("1st Exception"); 
} 
try { 
 yield 2; 
} catch(e) { 
 console.log("2nd Exception"); 
}
}
const generator = generator_function();
console.log(generator.next().value);
console.log(generator.throw("exception string").value);
console.log(generator.throw("exception string").done);

运行上段代码将会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1
1st Exception
2
2nd Exception
true

从代码输出可以输出,当我们在generator.throw()方法时,被生成器内部上个暂停点的异常处理代码所捕获,同时可以继续返回下个暂停点的值。由此可见在生成器内部使用try...catch可以捕获异常,并不影响值的下次消费,遇到异常不会终止。

向生成器传递数据

生成器不但能对外输出数据,同时我们也可以向生成器内部传递数据,是不是很神奇呢,还是从一段代码开始说起:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function* generator_function(){ 
    const a = yield 12;
    const b = yield a + 1;
    const c = yield b + 2; 
    yield c + 3; // Final Line
}
const generator = generator_function();
console.log(generator.next().value);
console.log(generator.next(5).value);
console.log(generator.next(11).value);
console.log(generator.next(78).value);
console.log(generator.next().done);

运行上述代码将会输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
12
6
13
81
true

从上述代码我们可以看出:

  • 第一次调用generator.next(),调用yield 12,并返回值12,相当启动生成器。并在 yield 12 处暂停。
  • 第二次调用我们向其进行传值generator.next(5),前一个yield 12这行暂停点获取传值,并将5传递给a, 忽略12这个值,然后传递给 yield (a + 1) 这个暂停点,因此是6返回给value属性。并在 yield a + 1 这行暂停。
  • 第三次调用next,同理在第二处暂停进行恢复复,把11的值赋值给b,忽略a+1运算,因此在yield b + 2中,返回13,并在此行暂停。
  • 运行到最后一行,C变量被赋值78,最后一行为加法运算,因此value属性返回81。
  • 再次运行next()方法,done属性返回true,生成器数组消费完毕。

从步骤说明中,向生成器传递数据,首行的next方法是启动生成器,及时向其传值,也不能进行变量赋值,你可以拿上述例子进行实验,无论你传递什么都是徒劳的,因为传递数据只能向上个暂停点进行传递,首个暂停点不存在上个暂停点。

生成器示例应用

了解生成器的知识后,我们做些有趣的练习:

斐波那契数列

首先我们实现一个生成斐波那契数列的生成器函数,然后编写一个辅助函数用于进行控制输出,如下段代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function* fibonacciSequence() {  
    let x = 0, y = 1;  
    for(;;) {   
         yield y;    
        [x, y] = [y, x+y]; 
}}

function fibonacci(n) {  
    for(let f of fibonacciSequence()){    
        if (n-- <= 0) return f;  
        }}
console.log(fibonacci(20))   // => 10946

此函数只能返回指定位置的数值,如果返回指定位置的数列看起来会更加实用,如下段代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function* fibonacciSequence() {  
    let x = 0, y = 1;  
    for(;;) {   
         yield y;    
        [x, y] = [y, x+y]; 
}}

function* take(n, iterable) {  
    let it = iterable[Symbol.iterator](); 
      while(n-- > 0) {        
            let next = it.next();  
    if (next.done){
        return;
    }    
    else { 
        yield next.value
    }; 
}}

console.log([...take(5, fibonacciSequence())])
//[ 1, 1, 2, 3, 5 ]

多个生成器进行交错迭代

比如我们要实现一个zip函数功能,类似Python的zip函数功能,将多个可迭代的对象合成一个对象,合成对象的方法,就是循环依次从各个对象的位置进行取值合并,比如有两个数组a=[1,2,3],b=[4,5,6],合并后就是c=[1,4,2,5,3,6],如何用生成器进行实现呢?如下段代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function* oneDigitPrimes() { 
    yield 2;                   
    yield 3;               
    yield 5;                 
    yield 7;           
}
function *zip(...iterables) {  
    let iterators = iterables.map(i => i[Symbol.iterator]()); 
    let index = 0;  
    while(iterators.length > 0) { 
        if (index >= iterators.length)     
        index = 0;                       
        let item = iterators[index].next();   
        if (item.done) {                       
            iterators.splice(index, 1);      
            }
            else {
                yield item.value;                
                index++;
                }  
        }
}
console.log([...zip(oneDigitPrimes(),"ab",[0])]);
//[ 2, 'a', 0, 3, 'b', 5, 7 ]

从zip函数中我们可以看出:

  • 首先通过Map函数将传入的可迭代对象进行实例化。
  • 然后循环可迭代对象,通过yield关键字调用next()方法进行返回输出。
  • 直到对应生成器数值消费完毕,移除对应的生成器(迭代器)对象。
  • 直到所有的生成器函数数值消费完,循环迭代的对象为空,函数停止执行。

通过向后追加的形式合并可迭代对象成一个新对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function* oneDigitPrimes() { 
    yield 2;                   
    yield 3;               
    yield 5;                 
    yield 7;           
}
function* sequence(...iterables) {  
    for(let iterable of iterables) {   
         yield* iterable;  
        }}
console.log([...sequence("abc",oneDigitPrimes())])
//[ 'a', 'b', 'c', 2, 3, 5, 7 ]

使用生成器处理异步调用

假设有两个简单的异步函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let getDataOne=(cb)=>{
    setTimeout(function () {
        cb('response data one');
    }, 1000);
};
let getDateTwo=(cb)=>{
    setTimeout(function () {
        cb('response data two')
    }, 1000)
}

将上述代码改成使用Generator,我们使用next(value)的方法向生成器内部传值,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let generator;
let getDataOne=()=>{
    setTimeout(function () {
        generator.next('response data one');
    }, 1000);
};
let getDateTwo=()=>{
    setTimeout(function () {
        generator.next('response data two')
    }, 1000)
}

接下来我们来实现一个生成器函数main,调用上述方法,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *main() {
    let dataOne=yield getDataOne();
    let dataTwo=yield getDateTwo();
    console.log("data one",dataOne);
    console.log("data two",dataTwo);
}

怎么运行代码呢,其实很简单,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
generator=main();
generator.next();
//output
//data one response data one
//data two response data two

结果按照我们的预期进行输出,而且main()函数的代码更加友好,和同步代码的感觉是一致的,接下来是这样的:

  • 首先实例化生成器对象
  • 接下来我们调用next()方法,启动生成器,生成器在第一行暂停,触发调用getDataOne()函数。
  • getDataOne()函数在1秒钟后,触发调用generator.next('response data one'),向生成器main内部变量dataOne传值,然后在yield getDateTwo()此处暂停,触发调用getDateTwo()。
  • getDateTwo()函数在1秒钟后,触发调用generator.next('response data two'),向生成器main内部变量dataTwo传值,然后运行下面console.log的内容,输出dataOne,dataTwo变量的值。

你是不是发现一个异步调用就和同步调用一样,但它是以异步的方式运行的。

一个真实的异步例子

例如我们有一个需求,用NodeJs实现从论坛帖子列表数据中显示其中的一个帖子的信息及留言列表信息,代码如下:

DB/posts.json(帖子列表数据)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[
    {
        "id": "001",
        "title": "Greeting",
        "text": "Hello World",
        "author": "Jane Doe"
    },
    {
        "id": "002",
        "title": "JavaScript 101",
        "text": "The fundamentals of programming.",
        "author": "Alberta Williams"
    },
    {
        "id": "003",
        "title": "Async Programming",
        "text": "Callbacks, Promises and Async/Await.",
        "author": "Alberta Williams"
    }
]

DB/comments.json(评论列表)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[
    {
        "id": "phx732",
        "postId": "003",
        "text": "I don't get this callback stuff."
    },
    {
        "id": "avj9438",
        "postId": "003",
        "text": "This is really useful info."
    },
    {
        "id": "gnk368",
        "postId": "001",
        "text": "This is a test comment."
    }
]

用回调的方法实现代码如下 index.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const fs = require('fs');
const path = require('path');
const postsUrl = path.join(__dirname, 'db/posts.json');
const commentsUrl = path.join(__dirname, 'db/comments.json');
//return the data from our file
function loadCollection(url, callback) {
    fs.readFile(url, 'utf8', function(error, data) {
        if (error) {
            console.log(error);
        } else {
            return callback(JSON.parse(data));
        }
    });
}
//return an object by id
function getRecord(collection, id, callback) {
    var collectobj=collection.find(function(element){
        return element.id == id;
    });
    callback(collectobj);
    return collectobj;
}
//return an array of comments for a post
function getCommentsByPost(comments, postId) {
    return comments.filter(function(comment){
        return comment.postId == postId;
    });
}
loadCollection(postsUrl, function(posts){
    loadCollection(commentsUrl, function(comments){
        getRecord(posts, "001", function(post){
            const postComments = getCommentsByPost(comments, post.id);
            console.log(post);
            console.log(postComments);
        });
    });
});

如果用生成器的方法如何实现呢?首先我们改写loadCollection方法,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let generator;
function loadCollection(url) {
    fs.readFile(url, 'utf8', function(error, data) {
        if (error) {
            generator.throw(error);
        } else {
            generator.next(JSON.parse(data));
        }
    });
}

接着我们完成main generator 函数的实现,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function *main() {
    let posts=yield loadCollection(postsUrl);
    let comments=yield loadCollection(commentsUrl);
    getRecord(posts, "001", function(post){
                const postComments = getCommentsByPost(comments, post.id);
                console.log(post);
                console.log(postComments);
            });
}

最后我们进行调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
generator=main();
main().next();

将一个回调机制转换成一个生成器函数,看起来是不是很简洁易懂呢,我们很轻松的创建了看似同步的异步代码。

小节

关于生成器(Generator)的介绍就到这里,它可以通过next方法暂停和恢复执行的函数。next方法还具备向生成器传递数据的功能,正是得益这个特点,才能帮助我们解决异步代码的问题,让我们创建了看似同步的异步代码,对于我们来说这个神器是不是特别的强大。

注:本文参考《javascript ES6 函数式编程入门经典》、《你不知道的javascript》、《The Definitive Guide, 7th Edition》

【ES6基础】let和作用域

【ES6基础】const介绍

【ES6基础】默认参数值

【ES6基础】展开语法(Spread syntax)

【ES6基础】解构赋值(destructuring assignment)

【ES6基础】箭头函数(Arrow functions)

【ES6基础】模板字符串(Template String)

【ES6基础】Set 与 WeakSet

【ES6基础】Map 与 WeakMap

【ES6基础】Symbol介绍:独一无二的值

【ES6基础】Object的新方法

【ES6基础】迭代器(iterator)

【数据结构基础】栈简介(使用ES6)

【数据结构基础】队列简介(使用ES6)

【css基础】如何理解transform的matrix()用法

更多精彩内容,请微信关注”前端达人”公众号!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
「数据管理」顶级数据库管理系统供应商
确定哪种类型的数据库或数据库服务最适合您的企业的最佳方法是什么?这完全取决于您需要什么类型的用例。在本文中了解更多信息。
架构师研究会
2019/12/24
1.7K0
数据库基础知识总结
转载请注明:http://blog.csdn.net/uniquewonderq
MickyInvQ
2020/09/27
7530
数据库技术发展与非关系型数据库NoSQL:
近几年来,NoSQL运动如火如荼,不断有业内的巨头加入阵营,发布和推广NoSQL的相关产品,开拓应用场景。传统关系型数据库软件厂商也不甘寂寞,新产品、新版本、新特性不断发布,新官司、新收购也频频爆出,即使一向沉静的数据库市场,也被震出了几丝波澜。
Enjoy233
2019/03/05
1.9K0
常用的数据库管理系统软件有哪些?
目前互联网中比较常用的数据库管理系统有SYBASE、DB2、ORACLE、MySQL、ACCESS、Visual Foxpro、MS SQL Server、Informix、PostgreSQL这几种。
chenzhouliyan
2019/08/06
17.5K0
多维数据库概述之一---多维数据库的选择
1. 多维数据库简介 多维数据库(Multi Dimesional Database,MDD)可以简单地理解为:将数据存放在一个n维数组中,而不是像关系数据库那样以记录的形式存放。因此它存在大量稀疏矩阵,人们可以通过多维视图来观察数据。多维数据库增加了一个时间维,与关系数据库相比,它的优势在于可以提高数据处理速度,加快反应时间,提高查询效率。MDD的信息是以数组形式存放的,所以它可以在不影响索引的情况下更新数据。因此MDD非常适合于读写应用。 1.1. 关系数据库存在的问题 利用SQL进行关系数据库查询的局限性: 1) 查询因需要“join”多个表而变得比较烦琐 ,查询语句(SQL) 不好编程; 2) 数据处理的开销往往因关系型数据库要访问复杂数据而变得很大。 关系型数据库管理系统本身局限性: 1) 数据模型上的限制 关系数据库所采用的两维表数据模型,不能有效地处理在大多数事务处理应用中,典型存在的多维数据。其不可避免的结果是,在复杂方式下,相互作用表的数量激增,而且还不能很好地提供模拟现实数据关系的模型。关系数据库由于其所用数据模型较多,还可能造成存储空间的海量增加和大量浪费,并且会导致系统的响应性能不断下降。而且,在现实数据中,有许多类型是关系数据库不能较好地处理的 。 2) 性能上的限制 为静态应用例如报表生成,而设计的关系型数据库管理系统,并没有经过针对高效事务处理而进行的优化过程。其结果往往是某些关系型数据库产品,在对GUI和Web的事务处理过程中,没有达到预期的效果。除非增加更多的硬件投资,但这并不能从根本上解决问题。 用关系数据库的两维表数据模型,可以处理在大多数事务处理应用中的典型多维数据,但其结果往往是建立和使用大量的数据表格,仍很难建立起能模拟现实世界的数据模型。并且在数据需要作报表输出时,又要反过来将已分散设置的大量的两维数据表,再利用索引等技术进行表的连接后,才能找到全部所需的数据,而这又势必影响到应用系统的响应速度。 3) 扩展伸缩性上的限制 关系数据库技术在有效支持应用和数据复杂性上的能力是受限制的。关系数据库原先依据的规范化设计方法,对于复杂事务处理数据库系统的设计和性能优化来说,已经无能为力。此外,高昂的开发和维护费用也让企业难以承受。 4) 关系数据库的检索策略,如复合索引和并发锁定技术,在使用上会造成复杂性和局限性。 1.2. 多维数据库的相关定义 维(Dimension):是人们观察数据的特定角度,是考虑问题时的一类属性,属性集合构成一个维(时间维、地理维等)。 维的层次(Level):人们观察数据的某个特定角度(即某个维)还可以存在细节程度不同的各个描述方面(时间维:日期、月份、季度、年)。 维的成员(Member):维的一个取值,是数据项在某维中位置的描述。(“某年某月某日”是在时间维上位置的描述)。 度量(Measure):多维数组的取值。(2000年1月,上海,笔记本电脑,0000)。 OLAP的基本多维分析操作有钻取(Drill-up和Drill-down)、切片(Slice)和切块(Dice)、以及旋转(Pivot)等。 钻取:是改变维的层次,变换分析的粒度。它包括向下钻取(Drill-down)和向上钻取(Drill-up)/上卷(Roll-up)。Drill-up是在某一维上将低层次的细节数据概括到高层次的汇总数据,或者减少维数;而Drill-down则相反,它从汇总数据深入到细节数据进行观察或增加新维。 切片和切块:是在一部分维上选定值后,关心度量数据在剩余维上的分布。如果剩余的维只有两个,则是切片;如果有三个或以上,则是切块。 旋转:是变换维的方向,即在表格中重新安排维的放置(例如行列互换)。 1.3. 多维数据库的特点 后关系型数据库的主要特征是将多维处理和面向对象技术结合到关系数据库上。这种数据库使用强大而灵活的对象技术,将经过处理的多维数据模型的速度和可调整性结合起来。由于它独有的可兼容性,对于开发高性能的交换处理应用程序来说,后关系型数据库非常理想.在后关系型数据库管理系统中,采用了更现代化的多维模型,作为数据库引擎。并且,这种以稀疏数组 为基础的独特的多维数据库架构,是从已成为国际标准的数据库语言基础上继承和发展的,是已积累了实践经验的先进而可靠的技术。 多维数据模型能使数据建模更加简单,因为开发人员能够方便地用它来描述出复杂的现实世界结构,而不必忽略现实世界的问题,或把问题强行表现成技术上能够处理的形态,而且多维数据模型使执行复杂处理的时间大大缩短。例如开发一个服装连锁店信息管理系统时,如果用关系数据库,就需要建立许多表,一张表用来说明每种款式所具有的颜色和尺寸,另一张表用来建立服装和供应商之间的映射,并表示它是否已被卖出,此外还需要建一些表来表示价格变化、各店的库存等等。每成交一笔生意,所有这些表都需要修改,很快这些关系数据库就会变得笨重而
用户1148526
2019/05/25
4.3K0
数据库MySQL——初识
  假设现在你已经是某大型互联网公司的高级程序员,让你写一个火车票购票系统,来hold住十一期间全国的购票需求,你怎么写?
星哥玩云
2022/08/18
3560
数据库MySQL——初识
数据库系统原理——概述「建议收藏」
不需要,但是懂一门编程语言有助于学习SQL server中的TL-SQL TL-SQL带有流程控制的SQL命令
全栈程序员站长
2022/11/15
2.7K0
数据库系统原理——概述「建议收藏」
史上最全分布式数据库概述
墨墨导读:在集中式数据库系统不能完全符合实际需要的形势下,集中式DB的“集中计算”概念向“分布计算”概念发展。分布计算主要体现在客户机/服务器模式的分布式数据库体系结构两个方面。
数据和云
2019/06/18
6.9K0
史上最全分布式数据库概述
针对我国——国产数据库进行分析
Oracle能在所有主流平台上运行(包括Windows),完全支持所有的工业标准,采用完全开放策略,可以使客户选择最适合的解决方案,对开发商全力支持。
用户10196776
2022/11/22
1.3K0
针对我国——国产数据库进行分析
MSSQL之一 数据库系统简介 与SQL Server 2008概述
SQL的全称是结构化查询语言(Structured Query Language),它是关系数据库中最常用的语言。SQL不仅可以管理数据库中的数据,而且可以管理关系数据库本身。为了避免各数据库产品之间的SQL语法不兼容,因此由ANSI(American National Standard Institute,美国国家标准局)制定SQL-92标准,目前,大部分DBMS产品都支持该标准。
张哥编程
2024/12/13
1680
关系型数据库的发展历史[通俗易懂]
非关系型数据库:为适应水平扩展性和处理超大量的数据环境,近几年发展非常迅速的发展,衍生类型非常多。
全栈程序员站长
2022/09/13
4.6K0
关系型数据库的发展历史[通俗易懂]
数据库介绍
数据库系统(DBMS)是指一个能为用户提供信息服务的系统。他实现了有组织地、动态地存储大量相关数据的功能,提供了数据处理和信息资源共享的便利手段。
Breeze.
2022/05/01
3640
数据库介绍
数据库总结
常见的关系型数据库有mysql 、SQL Server、Oracle、Sybase、DB2等。关系型数据库是目前最受欢迎的数据库管理系统,技术比较成熟。
用户10048459
2022/10/11
1K0
Oracle数据库应用系统结构
在安装、部署Oracle数据库软件时,需要根据不同应用结构(即硬件平台、操作系统平台)采用不同的方法(基本安装、高级安装),下面介绍几种常见的应用结构。
数据和云
2019/08/01
1.1K0
Oracle数据库应用系统结构
第一章《初识数据库》
(1)什么是数据库: 硬盘—管理软件 数据库(DataBase、DB)是一个长期存储在计算机内、有组织的、有共享的、统一管理的数据集合。他简而言之就是一个存储数据的仓库。为了方便数据的存储和管理,他将数据按照特定的规律存储在硬盘上,通过数据库管理系统,可以有效的组织和管理存储再数据库中的数据。 我们也可以说数据库是由一批数据库的有序集合,这些数据被存放在结构化的数据表里。数据表之间相互关联、反映了客观事物间的本质联系。数据库系统提供对数据的安全控制和完整性控制。 2.数据库系统: 数据库系统由3部分组成: (1)数据库:用于存储数据的地方 (2)数据库管理系统:用于管理数据的软件 (3)数据库应用程序:为了提高数据库系统的处理能力所使用的管理数据的软件补充;
全栈程序员站长
2021/06/08
3200
第一章《初识数据库》
【数据库09】数据库系统体系结构
最早的数据库是在单台支持多任务的物理机器上运行的,这种集中式的数据库系统仍然在被广泛使用,如今在集中式数据库系统上运行的企业级应用可能拥有成千上万的用户,数据库的规模从兆字节到数百G字节不等。
半旧518
2022/11/22
7010
【数据库09】数据库系统体系结构
5个常用的MySQL数据库管理工具_sql数据库管理工具
工欲善其事,必先利其器。几乎每个开发人员都有最钟爱的 MySQL 管理工具,它帮助开发人员在许多方面支持包括 PostgreSQL,MySQL,SQLite,Redis,MongoDB 等在内的多种数据库;提供各种最新的特性,包括触发器、事件、视图、存储过程和外键,支持导入、数据备份、对象结构等多种功能。
全栈程序员站长
2022/09/25
10.6K0
5个常用的MySQL数据库管理工具_sql数据库管理工具
[每天五分钟,备战架构师-11]数据库系统
数据挖掘就是从大量的、不完全的、有噪声的、模糊的、随机的实际应用数据中,提取隐含在其中的、人们事先不知道的,但又是潜在有用的信息和知识的过程。
大江小浪
2018/09/19
1.9K0
数据库简介与 Mysql 服务基础「建议收藏」
  数据库管理系统(DatabaseManagementSystem,DBMS)是实现对数据库资源有效组织、管理和存取的系统软件。它在操作系统的支持下,支持用户对数据库的各项操作。
全栈程序员站长
2022/09/18
8100
数据库简介与 Mysql 服务基础「建议收藏」
oracle系列--第一篇 数据库基础
1.1 数据管理概述 1.1.1 什么是数据管理 与我们人类相比,计算机的最大优势就是能够高速、精准地运行,其运行的过程就是执行程序代码和操作指令、处理数据的过程。可以说,数据处理是计算机最基本的功能,而数据
Hongten
2018/09/13
3880
推荐阅读
相关推荐
「数据管理」顶级数据库管理系统供应商
更多 >
LV.1
这个人很懒,什么都没有留下~
目录
  • 什么是生成器?
  • 生成器的基本语法
  • yield关键字
  • 生成器函数的类型检测
  • yield*委托
  • return(value)方法
  • throw(exception)方法
  • 向生成器传递数据
  • 生成器示例应用
    • 斐波那契数列
    • 多个生成器进行交错迭代
    • 通过向后追加的形式合并可迭代对象成一个新对象
    • 使用生成器处理异步调用
    • 一个真实的异步例子
  • 小节
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档