Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 用fetchapi替换$http_Javascript_Angularjs_Angular Promise_Fetch Api_Angularjs Http - Fatal编程技术网

Javascript 用fetchapi替换$http

Javascript 用fetchapi替换$http,javascript,angularjs,angular-promise,fetch-api,angularjs-http,Javascript,Angularjs,Angular Promise,Fetch Api,Angularjs Http,我正在用Fetch API替换$http,并用Promise API替换$q。正因为如此,Angular不再运行摘要循环,因此UI不再呈现。为了解决这个问题,我尝试了Zone.js,这似乎部分解决了我们的问题。不幸的是,它的API在0.6中完全改变了,所以我们使用了 现在谈谈实际问题 刷新页面时,Angular会按预期配置和引导应用程序。在此阶段,我将初始化区域并装饰$rootScope.apply区域和$rootScope.$digest()。现在,当我在状态/路由之间转换(使用ui路由器)时

我正在用Fetch API替换
$http
,并用Promise API替换
$q
。正因为如此,Angular不再运行摘要循环,因此UI不再呈现。为了解决这个问题,我尝试了Zone.js,这似乎部分解决了我们的问题。不幸的是,它的API在0.6中完全改变了,所以我们使用了

现在谈谈实际问题

刷新页面时,Angular会按预期配置和引导应用程序。在此阶段,我将初始化区域并装饰
$rootScope.apply
区域和
$rootScope.$digest()
。现在,当我在状态/路由之间转换(使用ui路由器)时,一切都按预期工作,但当完全刷新时,会出现竞争条件,区域/摘要无法正确运行。我不知道怎么修

我在
angular.run()块中有以下代码:

console.log('Zone setup begin');
const scopePrototype = $rootScope.constructor.prototype;
const originalApply = scopePrototype.$apply;
const zoneOptions = {
    afterTask: function afterTask() {
        try {
            $rootScope.$digest();
        } catch (e) {
            $exceptionHandler(e);
            throw e;
        }
    }
};

scopePrototype.$apply = function $applyFn() : void {
    const scope = this;
    const applyArgs = arguments;

    window.zone.fork(zoneOptions).run(() => {
        originalApply.apply(scope, applyArgs);
        console.log('Zone + $digest run!');
    });
};
console.log('Zone setup end');
在上面,您可以看到,当区域初始化开始、结束和运行(+角度摘要周期)时,我会登录到控制台。在通过FetchAPI获取数据的控制器中,我添加了一个
console.log('datafetched!')这样我就知道什么时候提取了数据

现在,控制台中的输出:

使用ui路由器进行状态转换(工作正常)

请注意,摘要最后运行

Zone setup begin
Zone setup end
Zone + $digest run!
Zone + $digest run!
Zone + $digest run!
Zone + $digest run!
Data fetched!
Zone + $digest run!
状态/路由的完全刷新(最后不运行)


正如您所见,区域/摘要在获取数据后不会运行,这就是数据和UI不会呈现在页面上的原因。

将由创建的ES6承诺转换为AngularJS$q承诺

使用
$q.when
将ES6承诺转换为AngularJS承诺 AngularJS通过提供自己的事件处理循环来修改正常的JavaScript流。这将JavaScript分为经典和AngularJS执行上下文。只有在AngularJS执行上下文中应用的操作才会受益于AngularJS数据绑定、异常处理、属性监视等。。。由于承诺来自AngularJS框架之外,因此该框架不知道对模型的更改,也不更新DOM

使用
$q.when
将外部承诺转换为角度框架承诺:

var myRequest = new Request('flowers.jpg');

$q.when(fetch(myRequest)).then(function(response) {
    //code here
})
使用与AngularJS框架及其摘要周期正确集成的$q服务承诺

$q.when 将可能是值或(第三方)的对象包装为
$q
承诺。当您处理的对象可能是承诺,也可能不是承诺,或者承诺来自不可信任的来源时,这非常有用

根本原因 包装
$q.when
会起作用,但根据我的团队经验,包装非常挑剔,而且容易出错。例如,从
承诺的主体内部返回
$q.when
时,
函数仍将作为常规的
承诺
链接,并且在回调时不会得到$digest

它还要求所有作者理解两个外观非常相似的构造(Promise/$q)之间的区别,并关心异步调用的每一级的具体类型。如果您使用的是像
async
/
await
(它进一步抽象了承诺类型)这样的现代便利设备,那么您将遇到更多的麻烦。突然之间,您的代码中没有一个是框架无关的

我们的团队认为,值得投入一个大补丁来确保所有承诺(以及
async
/
await
关键字)“只起作用”,而无需额外考虑

丑陋?对但我们觉得这是一个不错的折衷方案


修补程序承诺回调以始终应用$rootScope 首先,我们针对
Promise
angular.run
块中安装修补程序:

console.log('Zone setup begin');
const scopePrototype = $rootScope.constructor.prototype;
const originalApply = scopePrototype.$apply;
const zoneOptions = {
    afterTask: function afterTask() {
        try {
            $rootScope.$digest();
        } catch (e) {
            $exceptionHandler(e);
            throw e;
        }
    }
};

scopePrototype.$apply = function $applyFn() : void {
    const scope = this;
    const applyArgs = arguments;

    window.zone.fork(zoneOptions).run(() => {
        originalApply.apply(scope, applyArgs);
        console.log('Zone + $digest run!');
    });
};
console.log('Zone setup end');
angular.module(…).run(normalizepromissesideeffects);
normalizepromissesideeffects.$inject=['$rootScope'];
函数normalizepromissesideeffects($rootScope){
附件适用于承诺方法(“then”);
附件适用于承诺方法(“捕获”);
附件适用于承诺方法(“最终”);
函数AttachScopeApplicationPromiseMethod(方法名){
const NativePromiseAPI=window.Promise;
const nativeImplementation=NativePromiseAPI.prototype[methodName];
NativePromiseAPI.prototype[methodName]=函数(…promiseArgs){
const newPromiseArgs=promiseArgs.map(wrapFunctionInScopeApplication);
return nativeImplementation.bind(this)(…新承诺人);
};
}
函数包装FunctionInscope应用程序(fn){
如果(!isFunction(fn)| fn.isScopeApplicationWrapped){
返回fn;
}
常量wrappedFn=(…参数)=>{
const result=fn(…args);
//之所以使用此API,是因为在AngularJS src中使用了$q
$rootScope.$evalAsync();
返回结果;
};
wrappedFn.isScopeApplicationWrapped=true;
返回包装n;
}
}
异步/等待
如果您想支持使用
async
/
await
,您还需要将Babel配置为始终按照承诺实现语法。我们使用了。

问题不包含plunk或有助于调试问题的内容,这是必须的$应用补丁看起来很可疑。从$q和$http切换到本机承诺和获取的原因是什么?您可以有效地消除Angular作为框架的一系列好处,并创建一系列问题。这看起来不是一个好的折衷方案。那是因为我无法复制这个。从$q和$http切换到本机promises和Fetch的原因是,最终目标是用React替换Angular。ui路由器(我们用于路由)现在支持路由到反应组件。一般来说,我建议避免隐性消化,因为它们会导致无法控制的混乱和糟糕的表现。合理的中间解决方案是创建