其他

开门大吉

沉积近一年后重新开张~~

Hello World

搞定异步编程(一)——使用高阶函数管理并行程序

nodejs对外宣称的最大优势就是所谓的异步io,利用异步io,可以并行执行互相没有依赖的网络、数据库等操作,在某些场景下,这种方式可以极大的提高站点的响应速度
但是异步io也带来了代码本身逻辑的复杂性,比如一个应用,需要访问三个http数据源,然后综合比较三个数据源的结果,来得出最终的返回结果
三个数据源的回调执行顺序是不定的,这就需要一个计数器,在回调次数等于3时,再执行最终的处理程序
这里,借助js的高阶函数,来实现这个逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var _httpLib = require('./lib/http.js');  //简单的http辅助类,如:get(url, callback)
//高阶函数
var pending = (function(callback){
  var count = 0, //计数
    returns = {};
  return function(key){
    count++;     //注册一个回调
    return function(data){
      count--;   //执行一个回调
      //按照并行逻辑的key保存返回结果
      returns[key] = data;
   //   returns[key] = data.substr(0, 100);
      if(count === 0){   //所有回调都执行以后,运行最终的逻辑
        callback(returns);
      }
    };
  };
});
//。。。怎么来准确的称呼done哪?
var done = pending(function(returns){
  //最终的处理逻辑
  console.log('all-------over');
  console.log(returns);
});
//三个并行数据源
_httpLib.get('http://www.baidu.com', done('baidu'));
_httpLib.get('http://www.qq.com', done('qq'));
_httpLib.get('http://www.jiangkl.com', done('jkl'));

~~~呵呵,看到一坨return、function,如果你还没晕,那么,恭喜你。反正我盯着这段代码看了不下10分钟,然后又执行了几次才算大概弄明白的
整个的逻辑,有点类似aop的思想,即对多个并行逻辑的回调做一个拦截、记录,这样可以更好的让程序员将注意力集中到业务逻辑上
pending是一个公用的并行处理函数
done是通过pending得到的具体的业务执行function,其回调参数就是前面提到的并行逻辑“最终的处理程序”
done()执行时,会将pending闭包内的计数器加1,同时返回一个function,作为httpget的回调
done()()执行时,计时器减1,同时将httpget的返回值保存
计数器减到0,“最终的处理程序”开始执行

———–
参考:http://www.infoq.com/cn/articles/generator-and-asynchronous-programming

Hello World 微信开发

玩转微信公号开发(九)——获取用户信息

这里的“用户信息”,指的是昵称、头像等信息,具体的:

1
2
3
4
5
6
7
8
9
10
11
12
{
    "subscribe": 1, 
    "openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M", 
    "nickname": "Band", 
    "sex": 1, 
    "language": "zh_CN", 
    "city": "广州", 
    "province": "广东", 
    "country": "中国", 
    "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0", 
   "subscribe_time": 1382694957
}

具体的接口是:
https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

这里的ACCESS_TOKEN获取方法可以参考本系列之前的文章

如果用户没关注,subscribe字段为0,没有nickname、headimgurl等字段,只有用户关注你的公众号,才能拿到上面的全部信息

你可以用这个接口取得用户基本信息,也可以那它判断当前用户是否关注你的公众号

早期的时候,微信对用户基本信息控制的比较严格,只有用户授权过才能拿到这些信息,而且,再次拿信息的话,还要重新授权

偶然才看到微信的文档有了升级,用户信息接口换成了这个新的:/user/info,免去了惹人厌的授权过程。这点小小的开放,让很多基于微信的活动方案成为可能【赞一个】

————–
转载请注明出处:http://www.jiangkl.com/2014/04/weixin_user_info

Hello World

玩转微信公号开发(八)——消息的排重与回复

随着微信公号系统的逐步完善,原来的许多机制都得到了升级、增强,这可以让我们公众号的表现更稳定,但有时,也会给我们带来一下麻烦,比如下面这段微信文档新增的内容

————————————————
微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。

关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime 排重。

假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。 这种情况下,可以使用客服消息接口进行异步回复。
————————————————

首先,如果后端没有复杂的逻辑,5秒足够了,但是如果不能保证5秒内回复消息,就只能调客服消息接口了,可惜客服接口属于高级接口,订阅号是没有的(坑爹啊!),并且,即使是订阅号,客服消息的限制也挺多

另外,所谓的“断掉连接,重新发起请求”并不靠谱,我自己扫码或者点按钮后就经常会收到重复消息,也就是说,第一个请求还没结束,的二个请求可能就来了。。。

综合这两点,我们其实可以搭建一种这样的回复方式:

一个消息来了以后,首先根据微信文档里提到的排重方式,比如使用fromusername/msgid/event/count/createtime做md5,作为key,来标示这个消息,在这个请求内,处理相关的业务逻辑,但处理结果不在这个消息内回复,而是放到类似redis的缓存内

再有消息来时,由于同一个消息重复发送,key也是相同的,首先检查redis有没有该消息key的回复内容存在,如果有,直接回复,如果没有,再走上面的逻辑

这样子,不但可以排重,还可以为自己的业务逻辑多争取些处理时间

 

————

转载请注明出处:http://www.jiangkl.com/2014/03/重复消息/ ‎

 

Hello World 业界杂谈

[转]别闯进Hybrid App的误区

【引言】

Hybrid App,一种开发模式,兼顾Web和Native的一种开发模式。有人说它把Web App扼杀在摇篮里,有人说它把Native App引向一个新阶段。我说,它是一把双刃剑,千万别闯进它的误区。本文是笔者在实践Hybrid App开发模式过程中总结出的一些经验教训,供读者参考。Hybrid App虽好,可万万不能仓促选择,盲目运用。

智能手机日益普及,移动互联网乱战日趋白热化,开发一个应用早就不是技术圈热议的话题,iOS和Android上的App已经成了每个互联网产品的标配。“唯快不破”也是中被移动互联网人尊为铁律,快速迭代,高效开发,低成本上线是每一个App开发团队追求的目标。同时,随着HTML 5的不断升温和智能手机硬件性能的提高,Hybrid App的概念应运而生。这种“Native搭台,HTML 5唱戏”的Hybrid App开发模式一时间受到各个开发团队追捧,快速进入了大量开发团队,成为主流开发模式。

Hybrid App优点众多,Web前端工程师0成本介入,不依赖版本的实时更新,快速实现跨平台需求,等等。而另一个方面,2012年Hybrid App的践行者Facebook决定大量弃用App中的HTML页面,转向更加Native化的方案。Facebook的这一举措也给Hybrid App方案的敲响了警钟,这似乎并不是一个完美的方案。

本文主要跟大家分享一下我团队和个人在Hybrid App的实践中遇到的问题,提醒大家不要闯进Hybrid App的误区。

误区一:为了HTML 5而Hybrid App。

HTML 5在Hybrid App模式中是一个最常被提起的概念。HTML 5作为一个HTML 4.0.1和XHTML 1.0的升级版,基于旧版本有更强大的表现功能,并加入了Local Storage等技术,确实为Web页面提供了更大的想象空间和更多的可能性。但HTML 5处在目前的发展阶段,受到浏览器兼容性和手机硬件性能水平的影响,它所能提供的功能与Native仍然有很大差距。

所以,我认为作为工程师要明确一款App采用Hybrid App模式的根本原因是什么。作为一款App其最根本的功能是满足使用者的需求,而并不是服务某项新技术。因此当决定采用Hybrid App去构建一款应用时,应该从应用本身功能特点和整个团队的开发资源配比统一考虑,是否有必要同时又有能力去驾驭一款“Native搭台,HTML唱戏”的Hybrid App。类似“HTML 5的时代已经到来,如果我们不这么做就变土鳖了,错过这场技术革新的大潮,终将被这个时代所淘汰”的话真不是一个有责任心的工程师应该发出的声音。

误区二:忽略关键因素

在谈到Hybrid App的场合我们更多提及的是它有诸多优点,如何架构一个Hybrid App,怎么让Web和Native和谐共处,然而Web开发中会被忽略的一些因素少被提起,这些因素又恰恰经常是一个Web页面能否正常运行在App中的决定性因素。

Web开发是基于PC的一种开发模式,开发者使用PC浏览器模拟App中的Web View进行调试。PC浏览器与手机Web View的区别是巨大的,能支配的CPU资源,最大占有的内存,运行的网络环境,鼠标操作与触控操作的区别,浏览器对CSS/JS的解析和对事件处理,等等。

App工程师,无论是iOS还是Android,最敏感的一个问题莫过于内存管理,而在Web开发则对这个问题没有过多注意。这就经常导致同一个功能界面Native实现中会通过一些技术手段,把内存容量控制在操作系统允许的范围内保证App正常运行。如果以Web方式接入App的页面没有一个明确的标准和严格的验收机制,相应的Web实现则不会过多考虑这方面的问题,而且浏览器也没有给前端工程师提供足够的Api支持处理内存问题,导致在某些条件下造成App无法正常运行,甚至Crash。

同样的问题会出现在网络环境方面,虽然现在wifi覆盖越来越广,3G网络也日益普及,但App运行的网络环境与PC相比仍然有着巨大差距,wifi和蜂窝网络的切换,基站变化等诸多因素都会导致网络间歇性断开。Web开发总是默认有一个稳定的网络环境,因此在对于不稳定网络环境问题的处理上也有所欠缺。没有明确的对于低速网络或不稳定网络访问的处理,在很多情况下这些页面也会非常不给面子。

误区三:富交互导致体验差

这里所谓的体验问题一分为二:一是与手机平台默认交互习惯不一致的体验,二是与同样功能Native界面存在的体验差距。

无论在Android还是iOS平台上,都有各自的一套交互习惯,包括视觉风格,界面切换,操作习惯等,与Web习惯完全不同。如果使用Web方式开发富交互的页面,或多页面功能就会出现这样的问题。

以iOS界面切换为例,系统风格是新界面自右向左推入,后退时界面自左向右推出,而旧界面保持状态。Web开发的默认习惯则是刷新页面,无论新载入页面或是后退,都会对页面进行刷新。因此使用Web模式开发多界面功能就面临这样的交互习惯差异,造成体验上的损失。当然Web方式也可模拟Native的交互方式,但这样的模拟首先提高了开发成本,有悖于最初的高效原则,从效果上看,也很难达到Native的流畅性。

另一个方面,也是上述提到的与Native相比,同样的功能在性能上存在巨大差距。Web界面上JS对HTML Node的操作需要消耗大量的CPU资源,手机CPU的性能还不能与PC相提并论,就算在智能手机之间,硬件水准也参差不齐,一个可以在iPhone 5上流畅运行的界面,跑到三星S III上很可能就卡住不动了。所以我们经常可以发现一些富交互页面上的操作无法达到令人满意的流畅度,而流畅度也正是用户评价一款App优劣的最直观因素。

误区四:跨平台

一次开发,跨平台运行是Web的优势,这也是很多App采用Hybrid模式的重要原因之一。兼容性问题在Web开发过程中往往不被关注,但当下智能手机的软硬件版本众多,兼容性绝对是一个不容忽视的问题。

以Android手机为例,诸多主流品牌都有各自定制过的操作系统,浏览器内核对JS和CSS的解析,事件处理等方面都存在区别。以HTC One为例重叠在一起的层在某些情况下会对点击事件透传,而其他多数平台则不存在这个问题。并且目前移动平台的开发框架还没有完全成熟,可以很好的解决兼容性问题。所以就要求开发者在开发过程中要对兼容性做充分测试,对于某些特殊版本进行特殊处理。

即使在相对统一的iOS平台,不同版本之间也存在较大差异。例如:在iOS 4.x版本中CSS甚至不支持position fix的属性,4英寸屏幕的设备无法很好的支持apple-mobile-web-app-capable属性,等等。

误区五:交互一致性。

交互一致性是一个非常容易被误读的概念,“一致性”经常被理解为同一个应用在各种平台和场景下要有一致性的体验。我认为在移动平台开发过程中,“一致性”应该是App视觉和交互习惯与其运行平台的习惯保持一致。而Web开发“一次开发,跨平台运行”的特性与此存在一定程度上的冲突。

以“返回上一页面”的操作为例,在iOS平台上在页面顶部始终存在一个44像素高的导航栏,左侧有一个返回按钮用于返回操作,而Android平台则习惯使用设备提供的返回键操作。这个返回按钮在iOS平台可以通过绝对地址的方式连接到任何其他页面,而在Android平台返回按钮和设备的返回键则可能指向不同的位置。

例如这样的一个流程:首页->列表->筛选->刷新过的列表,此时的返回操作被期望是导向首页,则页面上的返回按钮可以通过绝对链接的方式实现,而Android设备的返回键则只能返回上一个筛选页面,再次返回是筛选前的列表页。

Hybrid App方案是一把双刃剑,一方面它平衡了Native App和Web页面的优缺点,一定程度上解决了Native App开发过程中迭代慢,版本依赖,Native开发资源不足的问题,但另一个方面过度依赖Hybrid方案会造成Web前端开发成本快速上升,甚至造成App整体体验下降,甚至造成功能缺失。

不要为了Hybrid而Hybrid,控制好方案中Native与Web的边界。

扩展阅读

较早Mobtest针对Facebook的iOS App专门做的一片评测文章,阐述了使用大量HTML页面的App出现的问题:http://blog.mobtest.com/2012/05/heres-why-the-Facebook-ios-app-is-so-bad-uiwebviews-and-no-nitro/

资深开发者@李秉骏 在InfoQ发表的《Hybrid App实战》,阐述了Hybrid模式的优势与劣势,并简单介绍了开发Hybrid App所需的技术储备,供读者参考。:http://www.infoq.com/cn/articles/hybrid-app-development-combat

资深开发者@唐巧 较早对Hybrid App主流框架PhoneGap的分析文章,笔者非常同意对PhoneGap框架的态度,PhoneGap虽好,可不要贪杯哟:http://blog.devtang.com/blog/2012/03/24/talk-about-uiwebview-and-phonegap/

————–
转自infoq:http://www.infoq.com/cn/articles/hybridapp-misunderstanding

Hello World 微信开发

玩转微信公号开发(七)——账号体系与oauth登录

默认情况下,如之前“接收消息”里所说,一个用户和微信公号发生交互是,开发者拿到的是用户的openId,每一个用户,对应每一个公号,都有唯一的一个openId,当用户使用微信内置webview访问我们的页面是,开发者可以调用oauth2.0协议,302到自定的url,获取访问者的openId

1
2
3
4
5
$redirect = 'http://xxxx.xxx.com/xxx';
$url = 'http://open.weixin.qq.com/connect/oauth2/authorize?appid=your-appid&redirect_uri='
   .$redirect.'&response_type=code&scope=snsapi_base&state=ubox#wechat_redirect';
$this->redirect($url);
exit;

其中,scope=snsapi_base是要获取的权限类型,snsapi_base获取的只是openId,snsapi_userinfo可以用户获取用的较详细的昵称、头像等内容,但是是需要用户授权
上面的$redirect,就是登陆后需要跳转回来的开发者服务器的地址,这个登录操作是自动的,不需要用户做操作
跳回以后,url后附加一个code参数,通过这个code,再调微信的对应接口,即可获得openId,或者userinfo

1
2
3
4
5
6
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=your-appid&secret=your-appSecret&code='.
	$_GET['code'].'&grant_type=authorization_code';
$json = Http::httpsGet($url);
$wxInfo = json_decode($json, true);
$openId = $wxInfo['openid'];
//.....你的其他操作

取得json的接口如下:

1
2
3
4
5
6
7
{
  "access_token":"xxxxxxxxxxxxxxxxxxxxxxxx",
  "expires_in":7200,
  "refresh_token":"xxxxxxxxxxxxxxxxxxxxxxxx",
  "openid":"ogaN_jp4sLWa4ZXGu5L39SSKcXU8",
  "scope":"snsapi_base,"
}

如你所见,openid就在里面了,进一步的,有了access_token,scope值如果是snsapi_userinfo,那么你还可以调“/sns/userinfo”接口取用户昵称等信息
expires_in是token超时时间,refresh_token可以用来刷新access_token

————
转载请注明出处: http://www.jiangkl.com/2014/02/weixin_oauth_userinfo/

Hello World

html:405 Not Allowed

刚刚发现一个nginx使用中的问题:当以post方式访问一个静态页面时,nginx会返回:405 Not Allowed
临时的解决方法是,把.html后缀变了了.php,O(∩_∩)O哈哈~
搜了一下更说的过去的解决办法,需要修改nginx的默认配置,转换静态文件接收的POST请求到GET方式。:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
upstream static_backend {
    server localhost:80;
}
 
server {
    listen 80;
 
    # ...
 
    error_page 405 =200 @405;
    location @405 {
        root /srv/http;
        proxy_method GET;
        proxy_pass http://static_backend;
    }
}

————
转载请注明出处:http://www.jiangkl.com/2014/02/nginx_html_405

Hello World 微信开发

玩转微信公号开发(六)——设置菜单

这里要讲的是,在开发模式下,如何自定义菜单

因为可能有中文乱码的问题,所以这里直接拼json串,然后调接口,post就ok了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public function weixin_custom_menu(){
	$token 		= WXUtil::getAccessToken();
	$url 			= "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=".$token;
	$msg 		= '{"button":['
		//单菜单
		.'{"type":"click","name":"现在购买","key":"BTN_1"},'
		.'{"type":"click","name":"优惠活动","key":"BTN_2"},'
		.'{"name":"帮助",//多级菜单
			"sub_button":[
					{"type":"view","name":"下载","url":"http://xx.com/download.html"},
					{"type":"view","name":"使用教程","url":"http://xx.com/howbuy.html"},  
					{"type":"view","name":"关于我们","url":"http://xx.com/about.html"}
				]
			}
		]}';
	echo $msg;
	$r 		= Http::httpsPost($url, $msg);
	print_r($r);//打印结果,返回error为0的话,即为设置成功
	exit;
}

参数说明

  • type,按钮的类型
    1. click,按钮,点击后,发送给开发者网关一个事件
      view,链接,打开一个webview页面,页面地址为url字段指定
  • name,按钮的显示名称
  • key,事件标示,对应本系列第二篇里提到的EventKey字段
  • url

菜单设置后,通常需要退出公众号再进一次才能生效,如果还不行,只能取消关注、再关注一次

————
转载请注明住处:http://www.jiangkl.com/2014/01/weixin_custom_menu

Hello World 微信开发

玩转微信公号开发(五)——发送主动消息

解决了access_token的问题,让我们来看看怎么主动给用户发消息

主动消息有两类,客服消息和模板消息,微信对滥发消息很敏感,所以对这两个功能限制很多,并且,这两个功能也都术语高级接口

客服消息

顾名思义,客服消息是给客服用的,具体限制是:用户给公众号发送过消息后(发送消息、菜单点击、支付成功、用户维权、扫描带参数二维码、订阅),48小时内,开发者可以调用客服消息接口,给该用户发送消息,消息的类型可以是文本、图片、语音、视频、音乐、图文,数据的格式是json~~注意,除了前面讲到的同步回复消息疑问,以后和微信的交互的数据格式都是json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
	//$data可以是字符串,也可能是数组,随具体的$type而改变
	public function sendCustom($openId, $data, $type = 'text'){
		$msg 		= array(
			'touser'		=> $openId,
		);
		switch($type){
			case 'text':
				$msg['msgtype'] = 'text';
				$msg['text'] 	= array('content' => urlencode($data));
				break;
			case 'image':
				$msg['msgtype'] = 'image';
				$msg['image'] 	= array('media_id' => $data);
				break;
			case 'voice':
				$msg['msgtype'] = 'voice';
				$msg['voice'] 	= array('media_id' => $data);
				break;
			case 'video':
				$msg['msgtype'] = 'video';
				$msg['video'] 	= $data;
				break;
			case 'music':
				$msg['msgtype'] = 'music';
				$msg['music'] 	= $data; 
				break;
			case 'news':
				$msg['msgtype'] = 'news';
				foreach($data as $k => $v){
					if(isset($v['title'])) $v['title'] = urlencode($v['title']);
					if(isset($v['description'])) $v['description'] = urlencode($v['description']);
					$data[$k] 	= $v;
				}
				$msg['news'] 	= array('articles' => $data);
				break;
		}
		$url 		= 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token='.self::getAccessToken();
		$postData 	= urldecode(json_encode($msg));
		$r 		= Http::httpsPost($url, $postData, true, false);
		return $r;
	}

getAccessToken,是在取access_token
httpsPost和上次说的httpsGet类似,只多了下面的两行,$input即为post的内容:

1
2
	curl_setopt($ch, CURLOPT_POST, true);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $input);

模板消息

模板消息,没有上面客服消息的限制,但是必须在微信提供的模板框架内拼出消息,如果用户想使用自己的模板,需要特别申请~~基本上很难
首先,从微信公号后台挑选可用的模板,拿到templateId,然后拼装下面结构的post参数:

1
2
3
4
5
6
7
8
$postData = array(
	"touser"	=> $openId,//接受者
	"template_id"	=> $templateId,
	//data为模板内的实际内容,字段项目视具体模板而定
	"data"		=> array("NAME"=>"里斯之泪", "PRICE"=>"¥10000.00"),
	"url"		=> "http://xxxx.xxx.com/xxxx",
	"topcolor"	=> "#333",//顶栏颜色
);

然后整理数据、调用接口就ok了

1
2
$postData 	= json_encode($postData);
$r 		= Http::httpsPost($url, $postData);

————
转载请注明出处: http://www.jiangkl.com/2014/01/custom-send_template/

幻界杂谈 日志

冰火志

《冰与火之歌》,史诗级的魔幻巨著,已出版的五部、15本,总共应该有五千余页~~~~~历时九个月,终于读完了

上班不读,在家不读,只在上下班的地铁里,每天不到一小时~~已经用这种方式读完了基地系列和冰与火系列,下一步要读哪个,还没目标,或许会把阿瑟克拉克的再读一遍,或者远望系列、沙丘系列

还是回来说冰与火吧,整部书的发生在一个虚构的世界里,社会形态类似中世纪的欧洲,大部分是“人间”的故事,魔法的成分很少

 

骑士、领主、封臣、奴隶、国王、学士

城堡、王国、草原、荒漠、大海、自由贸易城邦

铁卫、海盗、马帮、佣兵、野人、守夜人

心树、光之王、魔龙、冰原狼、异鬼、尸鬼、魔法

长矛、匕首、长剑、弯刀、战锤、野火、龙晶、瓦雷利亚钢

爱与恨、情与怨,忠诚与背叛、聪明与愚蠢、坚强与懦弱、仁爱与残忍、诺言与谎言、欲望、无耻

诸多关键字,勾勒出了一个庞杂的故事背景,让各色人等争相表现自己的爱恨情仇与喜怒哀乐

 

史塔克、坦格利安、拜拉席恩、兰尼斯特、提利尔、佛雷、波顿、马泰尔、徒利、葛雷乔伊……

一个家族就是一支力量、一段历史,若干家族,一起演义维斯特洛几千年的历史

 

丹妮莉丝、琼恩、提利昂、艾丽娅、凯瑟琳、布蕾妮、詹姆、瑟曦……

马丁老爷子借助他们的眼睛和视角,将故事为我们娓娓道来

 

同样作为国王,罗柏与丹妮对婚姻的选择,向我们展示什么叫不成熟

同样作为女王,瑟曦与丹妮对属下的态度,向我们展示什么叫大愚若智

所以,故事的解决似乎很明显,丹妮会一统天下,然而,马丁老爷子有不是按套路出牌的人,故事的解决究竟会怎样,或许只有他老人家自己知道

“欲知后事,且听下回”,第五部的结尾,为我们留下了一个无比开放的场面:

北方

正准备南下对付波顿的琼恩被捅了一刀,已经进入长城的野人和黑衣人之间脆弱的和平会被打破吗?

拉姆斯给琼恩的信里说,斯坦尼斯死了,是真的吗?

冯凯兰尼斯特死了,君临的烂摊子如何收拾,提利尔会彻底把兰尼斯特干掉吗?

奴隶湾

维克塔利昂率领的铁舰队对奴隶湾的战局会有什么影响?

贾科卡奥会帮助丹妮莉丝吗?

无畏的巴利斯坦能掌控弥林的局面吗?能打破渊凯的围困吗?

最后,最大的疑问,龙之号角能顺利到达丹妮莉丝手里吗?